简体   繁体   English

创建一个List实例,其类型派生自基类和接口

[英]Create an instance of a List where the type derives from a base class and an interface

I have a class that will be storing objects that derive from a base class and implement an interface. 我有一个类,该类将存储从基类派生并实现接口的对象。 In this example, all the types derive from UIElement and implement my interface IDropTarget . 在此示例中,所有类型都派生自UIElement并实现我的接口IDropTarget

So in my class I have I can use generic type inference in a fantastic way to require this without restricting everything to a specific base class 所以在我的课堂上,我可以用一种奇妙的方式使用泛型类型推断来要求它,而不必将所有内容都限制在特定的基类中

public void AddDropTarget<TTarget>(TTarget target)
    where TTarget : UIElement, IDropTarget
{
    target.DoSomethingAsUIElement();
    target.DoSomethingAsIDropTraget();

    // Now I want to save it for another method
    list.Add(target);
}

public void DoStuff()
{
    foreach(var item in list)
    {
        item.MoreUIElementAndDropStuff();
    }
}

Unfortunately, there seems to be no way for me to store this TTarget restricted list. 不幸的是,我似乎没有办法存储此TTarget受限列表。 I can't restrict it to a specific type because I have multiple classes that derive from UIElement already (Rectangle, Button, Grid, etc.), and there's no way for me to make all these object derive from a base type. 我不能将其限制为特定的类型,因为我已经有多个类从UIElement派生(矩形,按钮,网格等),而且我没有办法使所有这些对象都从基本类型派生。

My next solution is going to be storing a list of each type. 我的下一个解决方案是存储每种类型的列表。 I need to figure out if that overhead is worth it vs casting the objects each time I use them. 我需要弄清楚这些开销是否值得,而不是每次使用它们时都要投射对象。

You can not add two different types into a list this way. 您不能通过这种方式将两种不同的类型添加到列表中。 You are basically saying that you want they generic type to be either X OR Y . 你基本上是说,你想他们一般类型设置为XY Imagine what would happen when you did a foreach , the compiler would not know if you wanted a UIElement or a IDragDrop . 想象一下,当您进行一次foreach时会发生什么,编译器将不知道您是否需要UIElementIDragDrop

You just have to maintain type safety manually. 您只需要手动维护类型安全。 Use a private list (like you are doing, I assume) and then do the cast manually. 使用私有列表(我想就像您正在做的那样),然后手动进行投射。 It is up to you which type you want to use, or any. 取决于您要使用哪种类型或任何类型。

public class MyClass {

    private _list = new List<object>();  // don't store any type info for now

    public void AddDropTarget.... /* this is already correct */

    public void RunUiStuff() {
        // get all items that are of type UIElement.  Items of wrong type will be ignored
        foreach(var e in _list.OfType<UIElement>()) {

        }
    }

    public void RunDropStuff() {
        // cast works as well, but will throw if any object is not the correct type
        foreach(var e in _list.Cast<IDropTarget>()) {
        }
    }
}

If you don't want cast you can create the common base class you need with a variant of the decorator pattern. 如果您不想强制转换,则可以使用装饰器模式的变体来创建所需的公共基类。

//our new base type
public interface IElementAndDropTarget : IDropTarget
{
    void DoSomethingAsUIElement();
    void MoreUIElementAndDropStuff();
}

// our decorator. We need to store UIElement and IDropTarget
// as different fields. The static "Make" is giving you
// the compile-time guarantee that they both refer
// to the same class
public class UIElementDecorator : IElementAndDropTarget
{
    private readonly UIElement t;
    private readonly IDropTarget dt;

    private UIElementDecorator(UIElement t, IDropTarget dt)
    {   
        this.t=t;
        this.dt=dt;
    }

    public static UIElementDecorator Make<T>(T t) where T: UIElement, IDropTarget
    {
        return new UIElementDecorator(t,t);
    }

    public void DoSomethingAsUIElement() {t.DoSomethingAsUIElement();}
    public void MoreUIElementAndDropStuff(){t.MoreUIElementAndDropStuff();}
    public void DoSomethingAsIDropTarget() {dt.DoSomethingAsIDropTarget();}
}

with this, your list can be 这样,您的列表可以是

public List<IElementAndDropTarget> list = new List<IElementAndDropTarget>(); 

in AddDropTarget you can populate it with the decorated classes as: AddDropTarget ,可以使用修饰的类将其填充为:

list.Add(UIElementDecorator.Make(target));

and that's it. 就是这样。 The rest of your code can stay the same. 您的其余代码可以保持不变。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何强制一个类实现从特定基类/接口(而不是特定类型)派生的属性 - How to force a class to implement a property that derives from a specific base class/interface (rather than is of a specific type) 如何使用受约束的泛型类型参数将 class 实例化为派生接口 - How to instantiate a class as the interface that it derives from with constrained generic type parameter 创建从IEnumerable派生的接口 - Create interface which derives from IEnumerable 如何确定对象的类型是否实现了IEnumerable <X> 其中X使用Reflection从Base派生 - How to find out if an object's type implements IEnumerable<X> where X derives from Base using Reflection 实现一个泛型类,其中定义在基本接口类型上,但实现在从该基本接口派生的接口上? - Implement a generic class where the definition is on a base interface type but the implementation is on an interface derived from that base? 操作从列表或集合派生的 class - Manipulating a class that derives from a List or Collection 如何创建从实现接口的基类派生的实例列表? - How to create list of instances deriving from a base class that implements interface? 如何测试Type是否从抽象基类泛型类型派生? - How to test if Type derives from an abstract base generic type? 如何创建实现基本类型通用接口的类的实例 - How do I create instance of class implementing generic interface with base type 检查类型是否派生自具有多个通用参数的接口 - Check if a Type derives from a Interface with more than one Generic Argument
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM