c# - 使用 Wrapped<B> 类填充 Wrapped<A> 的集合,其中 B 实现 A

标签 c# oop generics inheritance

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

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; } );

The value "Reference[circle]" is not of type "Reference[shape]" and cannot be used in this generic collection.

有什么方法可以设计我的 Reference<T>这样的类只要A类型为 B , Reference<A>将被视为 Reference<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> 开始-> Reference<Shape>通过Reference<Circle> -> Circle -> Shape -> Reference<Shape> .但是,您将使用两个用户定义的隐式转换。首先你会从Reference<Circle> -> Circle通过operator T(Reference<T> value) .然后你会从 Shape -> Reference<Shape>通过operator Reference<T>(T value) .您可以通过扩展 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());

关于c# - 使用 Wrapped<B> 类填充 Wrapped<A> 的集合,其中 B 实现 A,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16802934/

相关文章:

c# - 使用 Roslyn SDK 生成器生成的自定义 SonarQube 规则始终发出类型 "Code Smell"

c++ - 访客模式+开放/封闭原则

oop - 重写伴随对象值和 Scala MatchError

c# - 将泛型 IEnumerable<T> 转换为 IEnumerable<KeyValuePair> (C#)

C# 泛型方法,不能隐式转换

java - LinkedList 的 add 方法(带有父类(super class)型)不是一切都好吗?

c# - 根据 C# 中对象列表中不同属性的值组合特定属性的值?

c# - Stackpanel IsMouseOver 为 False - 当鼠标悬停在 stackPanel Items 之间的间隙上时

c# - 向流畅的界面构建器添加 fork

c# - Xamarin.Forms 的 Plugin.BLE 未检测到设备