c# – 填充用W包装类包装的集合,其中B实现A

所以我有以下简单的包装类:

interface IReference<out T> where T : myAbstractBase {
    T Value { get; }
}
public class Reference<T> : IReference<T> where T : myAbstractBase
{
    private T _value = null;
    public T Value {  get { return _value; } }
}

在我的整个应用程序中,我希望拥有这些IReference的集合< someClass>对象(someClass实现myAbstractBase)

private List<Reference<shapes>> shapeList = new Collection<Reference<shapes>>();

但我希望能够为这个系列添加各种不同的形状. (特别是因为形状也是抽象的).当然,这会产生错误:

shapeList.Add( new Reference<circle>(){ radius = 2; } );

值“Reference [circle]”不是“Reference [shape]”类型,不能在此通用集合中使用.

有什么方法可以设计我的参考< T>这样,只要A是B类,参考< A>.将被视为类型参考< B>?

在我看来,人们会遇到尝试使用Nullable等列表的同类问题.

我已经尝试实现隐式运算符来在Reference和T之间进行转换,但我没有想到它们的任何实际用途……

public class Reference<T> ... {
    ...

    public static implicit operator Reference<T>(T value)
    {
        return new Reference<T> { _value = value, };
    }
    public static implicit operator T(Reference<T> value)
    {
        return value.Value;
    }
}

对于任何对我的意图感到好奇的人来说,这都是(命运多)尝试为一组类实现延迟加载而不必向这些类添加更多内容的一部分.

最佳答案 您的问题是您无法链接用户定义的隐式强制转换.乍一看,您似乎应该可以从Reference< Circle> – >参考和LT;形状>通过参考< Circle> – >圈 – >形状 – >参考和LT;形状取代.但是,您将使用两个用户定义的隐式转换.首先,你要从Reference< Circle> – >通过运算符T循环(参考< T>值).那你就去吧

形状 – >参考和LT;形状>通过运算符参考< T>(T值).您可以通过扩展List来创建Add方法的重载来解决这个问题.这将使您可以在Reference.Add中显式使用其中一个用户定义的强制转换运算符.现在,您不必链接用户定义的隐式转换运算符.

请参阅用户定义的隐式转换的规范:http://msdn.microsoft.com/en-us/library/aa691302(v=vs.71).aspx

//You can get around your inability to chain user defined implicit casts
//by creating a ReferenceList<T> that extends List<IReference<T>>
//and overloads the List.Add method
public class ReferenceList<T> : List<IReference<T>> where T : MyAbstractBase
{
    //With this overload you can accept a T.  Then explicity cast to Reference<T>
    //by using operator Reference<T>(T value)
    public void Add(T item)
    {
        base.Add((Reference<T>)item);
    }
}
List<Reference<Shape>> shapeList = new List<Reference<Shape>>();
ReferenceList<Shape> shapeList2 = new ReferenceList<Shape>();
List<IReference<Shape>> shapeList3 = new List<IReference<Shape>>();

//Interesting cases that should work with the OP

//Works for obvious reasons
shapeList.Add(new Reference<Shape>());
//Works because you're using one user defined implicit cast 
//where the cast is operator Reference<T>(T value).
//Shape -> Reference<Shape>
shapeList.Add(new Shape());
//Works because you're using one non user defined implicit cast and one user defined 
//implicit cast where the user defined implicit cast is operator Reference<T>(T value)
//Circle -> Shape -> Wrapper<Shape>
shapeList.Add(new Circle());
//Does not work because you need to chain two user defined implicit casts
//where the implicit casts are operator T(Reference<T> value) and operator Reference<T>(T value)
//Reference<Circle> -> Circle -> Shape -> Reference<Shape>
//Theoretically this could work, but the C# specs state that chaining user defined
//implicit casts is not allowed in C# (See link below)
shapeList.Add(new Reference<Circle>());
//This case works for similiar reasons that shapeList.Add(new Circle()).  It uses
//only one user defined implicit cast because you're calling operator T(Reference<T> value)
//explicitely  
shapeList.Add(new (Circle)Reference<Circle>());

//Interesting cases for ReferenceList

//Works because this calls List.Add which accepts a Reference<T>
shapeList2.Add(new Reference<Shape>());
//Works because this calls ReferenceList.Add wich accepts a T
shapeList2.Add(new Circle());
//Works because this calls ReferenceList.Add wich accepts a T.
//and Reference<Circle> can be implicitly cast to a Circle via
//operator T(Reference<T> value).
//Reference<Circle> -> Circle -> Shape -> Reference<Shape> where
//the last cast is done explicitely in the ReferenceList.Add method
//via operator Reference<T>(T value)
shapeList2.Add(new Reference<Circle>());

//Interesting cases for List<IReference<Shape>>


//Works for obvious reasons
shapeList3.Add(new Reference<Shape>());
//Works because IReference is covariant.  In C# interfaces can be
//covariant.  Classes cannot be covariant.
shapeList3.Add(new Reference<Circle>());
//Does not work because C# does not support user defined implicit
//casts to interface.  In other words, you implicitly cast Shape -> Reference<Shape>
shapeList3.Add(new Shape());
//Doesn't work for similiar reasons to why shapeList3.Add(new Shape()) doesn't work
shapeList3.Add(new Circle());
点赞