所以我有以下简单的包装类:
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());