C# 将结构作为通用协变参数放置

C# 将结构作为通用协变参数放置,c#,generics,struct,covariance,C#,Generics,Struct,Covariance,我有一个协变接口,它位于其父类型的数组中。 它们在全球范围内的定义如下: //The interface/class public interface IMyType<out T>{} public class MyType<T>: IMyType<T>{ T value; MyType<T>(T initialValue){ value = initialValue; } } //接口/类 公共接口IMy

我有一个协变接口,它位于其父类型的数组中。 它们在全球范围内的定义如下:

//The interface/class
public interface IMyType<out T>{}
public class MyType<T>: IMyType<T>{
    T value;
    MyType<T>(T initialValue){
        value = initialValue;
    }
}
//接口/类
公共接口IMyType{}
公共类MyType:IMyType{
T值;
MyType(T初始值){
值=初始值;
}
}
我试过这个:

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
};
IMyType[]tt=新的IMyType[]
{
新MyType(“测试”),//工作正常
new MyType(new SomeOtherRandomClass()),//工作正常
新MyType(12)//不工作
};

即使尝试指定结构而不是对象:

IMyType< struct>[] tt = new IMyType<struct>[]//Doesn't work:Incorrect Number of parameter
{
    new MyType<Int32>(12)//Doesn't work
};
IMyType[]tt=new IMyType[]//不起作用:参数数量不正确
{
新MyType(12)//不工作
};
仅指定特定结构有效:

IMyType< int>[] tt = new IMyType<int>[]//Does work
{
    new MyType<Int32>(12)//Does work
};
IMyType[]tt=新的IMyType[]//有效
{
新的MyType(12)//可以工作
};

那么为什么这不起作用呢?有没有办法让它工作?

接口
转换为
接口
作为协变转换是完全不可能的

原因是JITter必须为每个值类型编译单独版本的类(因为值类型具有不同的形状),因此它不能将其转换为任何其他通用实例化


方差仅适用于引用类型,因为引用都是相同的,所以JITted方法可以在不同的类型参数之间共享。

完全不可能将
接口
转换为
接口
,作为协变转换

原因是JITter必须为每个值类型编译单独版本的类(因为值类型具有不同的形状),因此它不能将其转换为任何其他通用实例化


方差只适用于引用类型,因为引用都是相同的,所以JITted方法可以在不同的类型参数之间共享。

如果您想完成将具有不同类型参数的泛型类型放入同一个集合的任务,并且由于提到的原因而不能使用方差,然后,您应该让泛型类型实现非泛型接口:

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
};
公共接口IMyType:ISomeBaseInterface{}
var tt=新接口[]
{
新MyType(“测试”),//工作正常
new MyType(new SomeOtherRandomClass()),//工作正常
新的MyType(12)//现在可以工作了
};

这可能足够,也可能不够,这取决于您的其他要求

如果要完成将具有不同类型参数的泛型类型放入同一个集合,并且由于上述SLaks的原因而无法使用协方差,则应让泛型类型实现非泛型接口:

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
};
公共接口IMyType:ISomeBaseInterface{}
var tt=新接口[]
{
新MyType(“测试”),//工作正常
new MyType(new SomeOtherRandomClass()),//工作正常
新的MyType(12)//现在可以工作了
};

这可能足够,也可能不够,这取决于您的其他要求

最好的解决方案可能是编写一个封装结构的包装类:

public class StructContainer<TStruct> where TStruct : struct
{
    TStruct value;
    public StructContainer(TStruct initialValue)
    {
        value = initialValue;
    }
}
公共类StructContainer,其中tsstruct:struct
{
t构造值;
公共结构容器(TStruct initialValue)
{
值=初始值;
}
}
然后你可以做:

IMyType<object>[] tt = new IMyType<object>[]
{
    new MyType<String>("test"), //Works fine
    new MyType<StructContainer<int>>(
        new StructContainer<int>(12)
    ) // compiles now
};
IMyType[]tt=新的IMyType[]
{
新MyType(“测试”),//工作正常
新MyType(
新容器(12)
)//现在编译
};
诚然,这牺牲了原始语法的简单性,并迫使您在以后需要从集合中提取项时执行hokey操作(如类型检查)


另一个选项是将对象集合和结构集合作为单独的集合进行跟踪。这可能更有意义,因为一旦您从列表中取出项目,您可能需要以不同的方式对待它们。

您最好的解决方案可能是编写一个封装结构的包装类:

public class StructContainer<TStruct> where TStruct : struct
{
    TStruct value;
    public StructContainer(TStruct initialValue)
    {
        value = initialValue;
    }
}
公共类StructContainer,其中tsstruct:struct
{
t构造值;
公共结构容器(TStruct initialValue)
{
值=初始值;
}
}
然后你可以做:

IMyType<object>[] tt = new IMyType<object>[]
{
    new MyType<String>("test"), //Works fine
    new MyType<StructContainer<int>>(
        new StructContainer<int>(12)
    ) // compiles now
};
IMyType[]tt=新的IMyType[]
{
新MyType(“测试”),//工作正常
新MyType(
新容器(12)
)//现在编译
};
诚然,这牺牲了原始语法的简单性,并迫使您在以后需要从集合中提取项时执行hokey操作(如类型检查)


另一个选项是将对象集合和结构集合作为单独的集合进行跟踪。这可能更有意义,因为一旦你从列表中取出项目,很可能你无论如何都需要以不同的方式对待它们。

struct
不是一种类型。
struct
是c#中的一个关键字,很像
class
isAnd
Int32
从技术上讲不是从
对象继承的。它继承自
ValueType
。Slaks/jaywayco:是的,我试着把
ValueType
放在这里,但也不起作用。ja72:不确定它是如何相关的?
struct
不是一个类型。
struct
是c#中的一个关键字,很像
class
isAnd
Int32
从技术上讲不是从
对象继承的。它继承自
ValueType
。Slaks/jaywayco:是的,我试着把
ValueType
放在这里,但也不起作用。ja72:不确定它是如何相关的?我可以创建结构的集合,但问题是我不能为每种类型的结构创建集合。可以列出所有泛型类型吗?据我所知,不是吗?否则,您的包装器对于meAs@SLaks似乎是可行的,您无法创建一个能够包含所有泛型类型的列表。但是,如果您想创建每种结构类型的列表,我建议您创建ValueType列表: