不允许使用通用接口的通用列表,有其他方法吗?

发布于 2024-10-08 23:51:25 字数 692 浏览 3 评论 0原文

我正在尝试找到使用通用接口的通用列表作为变量的正确方法。

这是一个例子。它可能不是最好的,但希望您能明白这一点:

public interface IPrimitive<T>
{
     T Value { get; }
}

然后在另一个类中,我希望能够声明一个变量,该变量包含实现 IPrimitive 的对象列表任意T

// I know this line will not compile because I do not define T   
List<IPrimitive<T>> primitives = new List<IPrimitives<T>>;

primitives.Add(new Star());   // Assuming Star implements IPrimitive<X>
primitives.Add(new Sun());    // Assuming Sun implements IPrimitive<Y>

请注意,对于列表中的每个条目,IPrimitive 中的 T 可能不同。

关于如何建立这样的关系有什么想法吗?替代方法?

I am trying to find the right way to use a Generic List of Generic Interfaces as a variable.

Here is an example. It is probably not the best, but hopefully you will get the point:

public interface IPrimitive<T>
{
     T Value { get; }
}

and then in another class, I want to be able to declare a variable that holds a list of objects that implement IPrimitive<T> for arbitrary T.

// I know this line will not compile because I do not define T   
List<IPrimitive<T>> primitives = new List<IPrimitives<T>>;

primitives.Add(new Star());   // Assuming Star implements IPrimitive<X>
primitives.Add(new Sun());    // Assuming Sun implements IPrimitive<Y>

Note that the T in IPrimitive<T> could be different for each entry in the list.

Any ideas on how I could setup such a relationship? Alternative Approaches?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

暮年 2024-10-15 23:51:26

你说它不起作用,因为你没有定义T。所以定义它:

public class Holder<T>
{
    public List<IPrimitive<T>> Primitives {get;set;}
}

You say it won't work because you don't define T. So define it:

public class Holder<T>
{
    public List<IPrimitive<T>> Primitives {get;set;}
}
水晶透心 2024-10-15 23:51:26

这是 C# 语言中最复杂的元素之一,尽管它对于构建定义良好的组件非常重要。因此,c# 还不够。然而,这绝对是可能的。

诀窍是由 3 个部分组成:

  1. 一个非通用接口,包含该接口的所有要求。
  2. 实现非泛型接口并根据需要执行类型转换的泛型抽象类。
  3. 使用适当类型化的结果实现通用抽象类的类

例如:

public interface INonGenericInterface{
    void Execute(object input);
    object GetModel();
}

public abstract class IGenericInterfaceBase<T> : INonGenericInterface{
    void INonGenericInterface.Execute(object input){
        Execute((T) input);
    }

    object INonGenericInterface.GetModel(){
        return GetModel();
    }

    protected abstract void Execute(T input);
    protected abstract T GetModel();
}

public class ImplementingClass : IGenericInterfaceBase<ModelClass>{
    protected override void Execute(ModelClass input){ /*Do something with the input */ }  
    protected override ModelClass GetModel(){ return new ModelClass();}
}

//Extras for demo
public class ModelClass { }
public class ModelClass2 { }

public class ImplementingClass2 : IGenericInterfaceBase<ModelClass2>
{
    protected override void Execute(ModelClass2 input) { /*Do something with the input */ }
    protected override ModelClass2 GetModel() { return new ModelClass2(); }
}

var agi = new INonGenericInterface[] { new ImplementingClass(), new ImplementingClass2() };
agi[0].Execute(); var model = agi[0].GetModel();
agi[1].Execute(); var model2 = agi[1].GetModel();
//Check the types of the model and model2 objects to see that they are appropriately typed.

这种结构在相互协调类时非常有用,因为您可以指示实现类将使用多个类并进行类型检查验证每个类都遵循既定的类型期望。此外,您可以考虑使用实际的类而不是非泛型类的对象,以便可以对各种非泛型调用的结果执行函数。使用相同的设计,您可以让这些类成为具有自己的实现的通用类,从而创建极其复杂的应用程序。

致OP:请考虑更改已接受的答案,以提高对正确方法的认识,因为之前给出的所有答案都因各种原因而达不到要求,并且可能给读者留下了更多问题。这应该可以处理与集合中的泛型类相关的所有未来问题。

This is one of the most complicated elements of the c# language though it is incredibly important for building well defined components. As such, c# falls short. However it is definitely possible to make this work.

The trick is to have 3 parts:

  1. A non generic interface that contains all requirements of the interface.
  2. A generic abstract class that implements the non generic interface and performs the type conversions as necessary.
  3. A class that implements the generic abstract class with the appropriately typed results

For example:

public interface INonGenericInterface{
    void Execute(object input);
    object GetModel();
}

public abstract class IGenericInterfaceBase<T> : INonGenericInterface{
    void INonGenericInterface.Execute(object input){
        Execute((T) input);
    }

    object INonGenericInterface.GetModel(){
        return GetModel();
    }

    protected abstract void Execute(T input);
    protected abstract T GetModel();
}

public class ImplementingClass : IGenericInterfaceBase<ModelClass>{
    protected override void Execute(ModelClass input){ /*Do something with the input */ }  
    protected override ModelClass GetModel(){ return new ModelClass();}
}

//Extras for demo
public class ModelClass { }
public class ModelClass2 { }

public class ImplementingClass2 : IGenericInterfaceBase<ModelClass2>
{
    protected override void Execute(ModelClass2 input) { /*Do something with the input */ }
    protected override ModelClass2 GetModel() { return new ModelClass2(); }
}

var agi = new INonGenericInterface[] { new ImplementingClass(), new ImplementingClass2() };
agi[0].Execute(); var model = agi[0].GetModel();
agi[1].Execute(); var model2 = agi[1].GetModel();
//Check the types of the model and model2 objects to see that they are appropriately typed.

This structure is incredibly useful when coordinating classes w/ one another because you're able to indicate that an implementing class will make use of multiple classes and have type checking validate that each class follows established type expectations. In addition, you might consider using an actual class instead of object for the non-generic class so that you can execute functions on the result of the various non-generic calls. Using this same design you can have those classes be generic classes w/ their own implementations and thus create incredibly complex applications.

To OP: Please consider changing the accepted answer to this to raise awareness of the correct approach as all previously stated answers fall short for various reasons and have probably left readers with more questions. This should handle all future questions related to generic classes in a collection.

信仰 2024-10-15 23:51:25
public interface IPrimitive
{

}

public interface IPrimitive<T> : IPrimitive
{
     T Value { get; }
}

public class Star : IPrimitive<T> //must declare T here
{

}

那么你应该能够拥有

List<IPrimitive> primitives = new List<IPrimitive>;

primitives.Add(new Star());   // Assuming Star implements IPrimitive
primitives.Add(new Sun());    // Assuming Sun implements IPrimitive
public interface IPrimitive
{

}

public interface IPrimitive<T> : IPrimitive
{
     T Value { get; }
}

public class Star : IPrimitive<T> //must declare T here
{

}

Then you should be able to have

List<IPrimitive> primitives = new List<IPrimitive>;

primitives.Add(new Star());   // Assuming Star implements IPrimitive
primitives.Add(new Sun());    // Assuming Sun implements IPrimitive
一个人的夜不怕黑 2024-10-15 23:51:25

约翰是正确的。

我是否还可以建议(如果您使用的是 C# 4)使您的接口协变?

public interface IPrimitive<out T>
{
     T Value { get; }
}

当您以后需要从列表中删除内容时,这可以为您节省一些麻烦。

John is correct.

Might I also suggest (if you are using C# 4) that you make your interface covariant?

public interface IPrimitive<out T>
{
     T Value { get; }
}

This could save you some trouble later when you need to get things out of the list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文