C#-一个列表中有多个泛型类型


152

这可能是不可能的,但是我有这个课:

public class Metadata<DataType> where DataType : struct
{
    private DataType mDataType;
}

还有更多,但让我们保持简单。泛型类型(DataType)受where语句限制为值类型。我要做的是列出这些不同类型(DataType)的元数据对象。如:

List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<int>());
metadataObjects.Add(new Metadata<bool>());
metadataObjects.Add(new Metadata<double>());

这有可能吗?


24
我想知道,与仅使用List<object>?相比,以下答案中的方法是否有任何真正的好处?他们不会停止装箱/拆箱,也不会消除铸造的需要,最终,您得到的Metadata物体无法告诉您任何有关实际的信息DataType,我正在寻找解决这些问题的解决方案。如果要声明一个接口/类,只是为了能够将实现/派生的泛型类型放入泛型列表中,那么与使用另一个具有无意义的层相比,它有何不同List<object>
Saeb Amini 2012年

9
抽象基类和接口都通过限制可以添加到列表中的元素的类型来提供一定程度的控制。我也看不到拳击是怎么来的。
0b101010 2014年

3
当然,如果您使用的是.NET v4.0或更高版本,那么协方差就是解决方案。List<Metadata<object>>绝招。
0b101010 2014年

2
@ 0b101010我也这么认为,但是不幸的是,值类型上不允许出现方差。由于OP具有struct约束,因此在这里不起作用。请参阅
nawfal 2014年

@ 0b101010,两者都只限制引用类型,仍然可以添加任何内置值类型和任何结构。同样,最后,您有一个MetaData引用类型列表,而不是原始值类型,而没有每个元素的基础值类型的(编译时)信息,这实际上是 “装箱”。
Saeb Amini

Answers:


195
public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
    private DataType mDataType;
}

5
哇!我真的认为这是不可能的!你是救生员,伙计!
卡尔,

2
+10!我不知道为什么会编译..正是我所需要的!
奥德斯

我有一个类似的问题,但是我的通用类是从另一个通用类扩展的,所以我不能使用您的解决方案...针对这种情况的解决方案有什么想法?
谢里登

10
与简单方法相比,此方法是否有好处List<object>?请查看我在OP的问题下发表的评论。
Saeb Amini 2012年

10
@SaebAmini List <object>不会向开发人员显示任何意图,也不会通过将一些非MetaData对象错误地添加到列表中来阻止开发人员自行射击。通过使用List <MetaData>,可以了解列表应包含的内容。MetaData最有可能具有一些上面示例中未显示的公共属性/方法。通过对象访问那些对象将需要繁琐的转换。
Buzz

92

按照leppie的答案,为什么不建立MetaData一个界面:

public interface IMetaData { }

public class Metadata<DataType> : IMetaData where DataType : struct
{
    private DataType mDataType;
}

有人可以告诉我为什么这种方法更好吗?
Lazlo 2010年

34
因为没有共享的通用功能-为什么在此基础上浪费基类?一个接口就足够了
flq 2010年

2
因为您可以在struct中实现接口。
DamianLeszczyński-Vash 2012年

2
但是,使用虚拟方法进行类继承的速度大约比接口方法快1.4倍。因此,如果您计划在MetaData <DataType>中实现任何非通用的MetaData(虚拟)方法/属性,那么如果考虑到性能,请选择一个抽象类而不是一个接口。否则,使用接口可以更加灵活。
TamusJRoyce 2012年

30

我还使用了非通用版本,使用了new关键字:

public interface IMetadata
{
    Type DataType { get; }

    object Data { get; }
}

public interface IMetadata<TData> : IMetadata
{
    new TData Data { get; }
}

显式接口实现用于允许两个Data成员:

public class Metadata<TData> : IMetadata<TData>
{
    public Metadata(TData data)
    {
       Data = data;
    }

    public Type DataType
    {
        get { return typeof(TData); }
    }

    object IMetadata.Data
    {
        get { return Data; }
    }

    public TData Data { get; private set; }
}

您可以派生一个针对值类型的版本:

public interface IValueTypeMetadata : IMetadata
{

}

public interface IValueTypeMetadata<TData> : IMetadata<TData>, IValueTypeMetadata where TData : struct
{

}

public class ValueTypeMetadata<TData> : Metadata<TData>, IValueTypeMetadata<TData> where TData : struct
{
    public ValueTypeMetadata(TData data) : base(data)
    {}
}

这可以扩展到任何种类的通用约束。


4
+1仅仅是因为您正在展示如何使用它(DataTypeobject Data帮助了很多人)
Odys

4
例如,我似乎无法写Deserialize<metadata.DataType>(metadata.Data);。它告诉我无法解析符号元数据。如何检索DataType以将其用于一般方法?
心教堂
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.