Search code examples
c#genericscode-contracts

Can I use code contracts to work around the inability to have generic constructor constraints?


I'm tying to write a class that will create immutable copies of another class, and the way I'm doing it requires that the copy takes a date and an instance of the original in the constructor. I know that you can't create a constructor constraint that specifies parameters, but is there a way to work around it using code contracts?

public class Copier<o, c>
    where o : class, INotifyPropertyChanged
    where c : class, c // ideally new(datetime, o)
{
    private Dictionary<DateTime, c> copies;

    public Copier(o original)
    {
        this.copies = new Dictionary<DateTime, c>();
        original.PropertyChanged += 
            this.propertyChangedHandler(object sender, PropertyChangedEventArgs args);
    }

    private void propertyChangedHandler(object sender, PropertyChangedEventArgs args)
    {
        var original = sender as o;
        var now = DateTime.Now;
        this.copies.Add(now, new c(now, original)); // error here
    }
}

The copy clases are created by me, inherit from the originals, override all of the properties to readonly and copy the values from the original in the constructor.

Note: There is a requirement (imposed by me) that the original objects cannot be modified.


Solution

  • As suggested, pass a creation delegate:

    public class Copier<o, c>
        where o : class, INotifyPropertyChanged
        where c : class, c // ideally new(datetime, o)
    {
    private Dictionary<DateTime, c> copies;
    private Func<o, DateTime, c> copyFunc;
    
    public Copier(o original, Func<o, DateTime, c> copyFunc)
    {
        this.copyFunc = copyFunc;
        this.copies = new Dictionary<DateTime, c>();
        original.PropertyChanged += 
            this.propertyChangedHandler(object sender, PropertyChangedEventArgs args);
    }
    
    private void propertyChangedHandler(object sender, PropertyChangedEventArgs args)
    {
        var original = sender as o;
        var now = DateTime.Now;
        this.copies.Add(copyFunc(now, original)); 
    }
    

    }