Put a struct as a generic covariant parameter

狂风中的少年 提交于 2019-12-24 20:18:01

问题


I've an Covariant interface, which is in an array of it's parent type. They are defined globally like this:

//The interface/class
public interface IMyType<out T>{}
public class MyType<T>: IMyType<T>{
    T value;
    MyType<T>(T initialValue){
        value = initialValue;
    }
}

I tried this:

IMyType< object>[] tt = new IMyType<object>[]
{
    new MyType<String>( "test"), //Works fine
    new MyType<SomeOtherRandomClass>(new SomeOtherRandomClass()),//works fine
    new MyType<Int32>(12)//Doesn't work
};

Even trying to specify a struct instead of object:

IMyType< struct>[] tt = new IMyType<struct>[]//Doesn't work:Incorrect Number of parameter
{
    new MyType<Int32>(12)//Doesn't work
};

Specifying only a specific struct works:

IMyType< int>[] tt = new IMyType<int>[]//Does work
{
    new MyType<Int32>(12)//Does work
};

So why does this not work? Is there a way to make it work?


回答1:


It is completely impossible to convert an Interface<ValueType> to Interface<object> as a covariant conversion.

The reason for this is that the JITter must compile a separate version of your class for each value type (since value types have different shapes), so it cannot convert it to any other generic instantiation.

Variance only works for reference types because references are all the same, so the JITted methods can be shared across different type parameters.




回答2:


Your best solution may be to write a wrapper class that encapsulates a struct:

public class StructContainer<TStruct> where TStruct : struct
{
    TStruct value;
    public StructContainer(TStruct initialValue)
    {
        value = initialValue;
    }
}

Then you could do:

IMyType<object>[] tt = new IMyType<object>[]
{
    new MyType<String>("test"), //Works fine
    new MyType<StructContainer<int>>(
        new StructContainer<int>(12)
    ) // compiles now
};

Granted, this sacrifices the simplicity of your original syntax and forces you to do hokey things (like type checks) later on when you need to pull items out of your collection.

One other option is to track a collection of objects AND a collection of structs as separate collections. This may make more sense because, again, once you pull items out of your list, it's likely that you'll need to treat them differently anyway.




回答3:


If you want to accomplish putting generic types with different type parameters into the same collection, and you can't use covariance for the reason SLaks mentioned, then you should have the generic type implement a non-generic interface:

public interface IMyType<out T> : ISomeBaseInterface {}

var tt = new ISomeBaseInterface[] 
{
    new MyType<String>( "test"), //Works fine
    new MyType<SomeOtherRandomClass>(new SomeOtherRandomClass()),//works fine
    new MyType<Int32>(12)//now it works
};

This may or may not be sufficient depending on what your other requirements are.



来源:https://stackoverflow.com/questions/28095804/put-a-struct-as-a-generic-covariant-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!