【问题标题】:How am I able to create A List<T> containing an open generic Interface?如何创建包含开放通用接口的 List<T>?
【发布时间】:2010-12-23 18:50:57
【问题描述】:

我有一个必须包含 IInteract 对象的列表。但IInteract 是一个通用接口,需要 2 个类型参数。

我的主要想法是遍历对象列表,如果它们尚未交互,则与另一个对象“交互”。 所以我有这个对象

List<IObject> WorldObjects = new List<IObject>();

还有这个:

private List<IInteract> = new List<IInteract>();

除了我无法编译最后一行,因为IInteract 需要 2 个类型参数。但在我添加它们之前,我不知道这些论点是什么。我可以添加类型 A 和 A 的对象之间的交互...或类型 B 和 C 的对象。

我想创建与“代理”对象和“目标”对象一起做某事的“交互”类,但我希望它们独立于对象......所以我可以在例如之间添加一个交互。 .. “SuperUltraClass” 和... “整数”

我是否使用了错误的方法?

【问题讨论】:

  • 你能告诉我们你的接口定义吗?我不确定我是否真的理解这个问题。
  • 我想做的是在我自己的“虚拟世界”中模拟交互。我希望他们通过包括我自己的一系列“交互”来进行交互。每个对象都有自己的线程,世界也是如此。这只是一个测试,我希望每个对象都按节奏工作,并且每次更新都发生在每个“世界”周期内。问题是:只要我觉得有必要,我想“包含”对象类型之间的交互。所以我可以添加两个“OlympicRunner”类并让它们参加比赛。或者我可以添加一个“OlympicRunner”和一个“Waitress”并让他们说话。

标签: c# list generics interface


【解决方案1】:

假设 IInteract 被定义为类似

interface IInteract<T1, T2>

并且您将它用于类 Foo 的字段:

class Foo
{
  List<IInteract...> field;
}

然后,如果您想推迟决定将哪些类型绑定到 IInteract 类型争论,您需要参数化容器类:

class Foo<T1, T2>
{
   List<IInteract<T1, T2>> field;
}

当您定义容器类的具体实例化时,此处 IInteract 的类型参数将被绑定,例如:var x = new Foo&lt;int, double&gt;(). 这将导致 IInteract 字段的类型为 IInteract&lt;int, double&gt;,用于 Foo 泛型类型的特定实例化.

【讨论】:

  • 但是当我实例化类时,我会被绑定到这两种类型,对吗?我希望列表存储不同类型的 IInteract
  • 是的,IInteract 接口将绑定到这两种类型,但仅限于容器类的特定实例化。如果您有另一对类型 T3 和 T4,您可以实例化容器类的另一个实例,并且该实例的 IInteract 将绑定到 T3 和 T4。您可以实例化容器类,从而将 IInteract 接口绑定到几乎无限数量的类型。
  • 如果您的意思是希望能够在运行时将 T1、T2 放入 IInteract 对象实例中,然后换档将 T3、T4 放入同一个 IInteract 实例中,那么泛型就不会出现来帮你。泛型提供了一种延迟类型决策的方法,但最终结果仍然是绑定到特定 T1、T2 类型的具体类型。您可以将同一泛型类型的多个具体实例绑定到不同的 T1、T2 类型参数,但您不能在同一个具体实例中混合和匹配不同的类型。
  • 前一种情况的替代方案(在中途切换齿轮以将 T3、T4 的实例放入 IInteract)是使用普通的旧 OOP 多态性技术。将您将放入 IInteract 的所有类定义为公共祖先类型的后代,或全部实现公共接口,然后将该公共祖先或接口类型指定为 IInteract 的 T1/T2 类型参数。在这种情况下,泛型并不能真正给你带来太多好处。
【解决方案2】:

我认为界面层次结构可能会使事情变得更容易。顶层可以是一个非泛型接口,只包含您需要调用的方法,没有任何类型信息。第二级是那些需要打字的……当然,简单地使用实现类而不是第二级接口可能就足够了。

public interface IInteract
{
    void Interact();
}

public interface IInteract<TActor,TTarget> : IInteract
{
    TActor Actor { get; set; }
    TTarget Target { get; set; }
}

然后您可以创建IInteract 对象列表,它可以包含任何强类型IInteract&lt;TActor,TTarget&gt; 对象,尽管只有非泛型接口上的那些方法可用。重要的是具体的实现——这将决定什么代码会被执行。

【讨论】:

    【解决方案3】:

    我认为您应该使用inversion of control 容器(我过去曾使用过Castle Windsor)。然后你可以这样做:

    void Interact<TA, TB>(TA objectA, TB objectB)
    {
        var interact = Container.Resolve<IInteract<TA, TB>>();
        interact.Interact(objectA, objectB);
    }
    

    【讨论】:

      【解决方案4】:

      你可以这样做:

      private List<IInteract<SomeType, SomeOtherType>> = new List<IInteract<SomeType, SomeOtherType>>();
      

      但是就像你说的你不知道你要添加什么类型。所以这里有几个选项:

      1:使用object(甚至dynamic)类型:

      private List<IInteract<object, object>> ...
      

      2:在你的类中使用泛型:

      class Foo<T1, T2> {
          private List<IInteract<T1, T2>> ...
      }
      
      ...
      
      Foo<string, int> bar = new Foo<string, int>();
      

      在第二个示例中,您只能将字符串和整数(或任何您创建的 Foo 对象)添加到列表中。在第一个示例中,您可以混合搭配,但您必须进行运行时类型检查才能确定您从列表中提取的内容。

      【讨论】:

      • 仅当 IInteract 在 T1 和 T2 中协变时,选项 1 才有效
      • 选项 1 似乎是我需要的,但它不适用于对象或动态。我该怎么投?
      【解决方案5】:

      我不确定我是否完全理解您要完成的工作。您需要做的是创建一个实现您的接口的具体类,然后在您的 List 中使用它。像这样:

      public interface IInteract
      {
         Type A { get; set; }
         Type B { get; set; }
      }
      
      
      public class Interact : IInteract
      {
          public Type A
          {
              get { return a; }
          }
      
          public Type B
          {
              get { return b; }
          }
      
      }
      

      然后在你的列表中使用你的具体类:

      private List<Interact> = new List<Interact>();  
      

      【讨论】:

        【解决方案6】:

        您最好使用字典,其中键是您正在交互的两种类型的元组,值是 Interact,因此每个 Interact 实现都必须进行一些转换

        private Dictionary<Tuple<Type, Type>, IInteract<Object, Object>> interactions = new Dictionary<Tuple<Type, Type>, IInteract<Object, Object>>();
        

        这有点乱,但你可以添加它:

        IInteract<Object, Object> superClassIntInteraction = someInteractionClass;
        interactions.Add(new Tuple<Type, Type>(typeof(SuperClass),typeof(int)), superClassIntInteraction);
        

        我假设您希望能够搜索列表/字典以便以后能够找到特定的交互,这就是字典派上用场的地方

        【讨论】:

          猜你喜欢
          • 2011-01-17
          • 1970-01-01
          • 1970-01-01
          • 2011-09-09
          • 2017-01-20
          • 2012-11-21
          • 1970-01-01
          • 2012-08-23
          • 2019-07-01
          相关资源
          最近更新 更多