1

Related to this earlier question: Casting to a generic class with interface and taking some cues from here: Casting interfaces for deserialization in JSON.NET

I have a class that looks something like this:

public MyClass<TEnum> where TEnum: struct, IConvertible
{
    public IBaseA<TEnum, abstractBaseClass> PropA { get; set; }
    public IEnumerable<IBaseB<TEnum, abstractBaseClass> PropB { get; set; }

    public MyClass(BaseA<TEnum, abstractBaseClass> propA, 
                   List<BaseB<TEnum, abstractBaseClass>> propB)  
    {
        PropA = propA;
        PropB = propB;
    }

    public MyClass() { }
}

Now I think I've got all my issues with BaseA and BaseB cleared up and I have JSON converters that can successfully produce those from JSON. The problem is this final parent class. I need to be able to either set PropA and PropB, or be able to pass in parameters to the constructor that are generics using classes derived from abstractBaseClass. For example:

 var foo = new MyClass<SomeEnum>(new BaseA<SomeEnum, DerivedClassA>(),
                                 new List<BaseB<SomeEnum, DerivedClassB>());

Doesn't compile.

Now I can do something like this:

var foo = new MyClass<SomeEnum>();
foo.PropB = new List<BaseB<SomeEnum, DerivedClassB>>();

But I can't figure out how to make this work in my JSON converter because while I can deserialize to a List<BaseB<SomeEnum, DerivedClassB>>, I can't assign it because at that point it's just an object and I can't cast it to the class I need. For example, if I try something like this:

foo.PropB = myJsonToken.ToObject<List<BaseB<SomeEnum, abstractBaseClass>>();

It'll compile, but fail at run time because the object deserializes as a List<BaseB<SomeEnum, DerivedClassB>> which isn't the same type.

I've tried various different takes on .ToObject, and serializer.Populate and just can't seem to find a way around this problem.

Update, this is what IBaseA and IBaseB look like:

public interface IBaseA<TEnum, out S>
    where TEnum: struct, IConvertible
    where S : abstractBaseClass
{
    TEnum Dim { get; }
    IEnumerable<ICVal<TEnum,S>> Include {get; }
}

public interface IBaseB<TEnum, out S>
    where TEnum: struct, IConvertible
    where S : abstractBaseClass
{
    TEnum Dim { get; }
    IEnumerable<S> Include { get; }
}
Community
  • 1
  • 1
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • Is `IBaseA` covariant, contravaraint, or invariant with respect to its first generic argument? What about its second generic argument? – Servy Jan 13 '15 at 19:27
  • `IBaseA` (and `IBaseB` for that matter) are invariant wrt to the first and covariant (marked with `out`) for the second generic parameter. – Matt Burland Jan 13 '15 at 19:33
  • What about `ICVal`? It would far easier to understand the question if you would provide [a good code example](https://stackoverflow.com/help/mcve) – Peter Duniho Jan 13 '15 at 20:56
  • That said, at first glance it seems that you are attempting to use contravariance where only covariance is allowed. I.e. you are assigned/passing-in the more-derived values, where you have only permitted the return of said values. Can you use `IReadOnlyList` instead of `List` in your assignment? – Peter Duniho Jan 13 '15 at 21:04

0 Answers0