【问题标题】:Call method on parameter of generic type调用泛型参数的方法
【发布时间】:2016-02-06 04:17:55
【问题描述】:

我想编写一个泛型方法,它作为输入具有泛型对象列表。我想对每个列表项调用一个方法。

我想做的是写这样的东西:

public void ResetPointProperties<T> (List<T> Points) 
{
    foreach (T point in Points)
    {
       point.Reset();
    }
}

如何在我的列表项上调用Reset()

【问题讨论】:

    标签: c# list generics methods


    【解决方案1】:

    你快到了。但是,缺少的是,就目前而言,编译器不知道每个T 是否/每个reset() 方法。因此,您必须将constraint 添加到T 参数,该参数要求T 实现接口或从声明此类reset() 方法的类继承。

    例如,让我们假设你在某个地方有以下接口:

    public interface IThing
    {
        void reset();
    }
    

    然后,您可以将上述方法声明如下:

    public void ResetPointProperties<T> (List<T> Points)
        where T : IThing
    

    这强制传递给T 类型参数的任何类型必须实现IThing。作为回报,编译器可以保证您的方法中的point 实际上有一个您可以调用的reset() 方法。

    【讨论】:

      【解决方案2】:

      如果您的问题是“我如何在T 上致电Reset(),那么-要正确执行-您需要引入generic type constraint

      您可以使用界面来执行此操作:

      public interface IResettable
      {
          void Reset();
      }
      

      并应用:

      public void ResetPointProperties<T> (List<T> Points)
          where T : IResettable
      

      现在,当您调用ResetPointProperties() 方法时,您必须使用List&lt;T&gt; 的参数来执行此操作,其中T 实现了接口IResettable。例如Point 类:

      public class Point : IResettable
      {
          public void Reset()
          {
              X = 0;
              Y = 0;
          }
      }
      

      【讨论】:

      • 虽然必须是:public void ResetPointProperties&lt;T&gt; (List&lt;T&gt; Points) where T : IResettable { ... 根据您的情况放置支架。
      • @Rinecamo 是的,谢谢,我没有注意就复制粘贴了 OP 的 Java 风格花括号。
      【解决方案3】:

      好的,让我们看看所有可能的方法:

      A.通用约束

      public void ResetPointProperties<T> (List<T> Points) 
         where T : ISomeInterface // interface must contain .Reset method
      {
          foreach (T point in Points)
             point.Reset();      
      }
      

      B.调用方法前的类型检查和显式转换:

      public void ResetPointProperties<T> (List<T> Points) 
      {
          if(typeof(T) != typeof(Point)) return;
      
          foreach (T point in Points)
          {
              Point p = point as Point;
              p.Reset();      
          }
      }
      

      C.通过反射:

      public void ResetPointProperties<T> (List<T> Points) 
      {
          if(typeof(T) != typeof(Point)) return;
          MethodInfo method = typeof(T).GetMethod("Reset");
      
          foreach (T point in Points)
          {
              t.Invoke(point, null);
          }
      }
      

      D.使用dynamic

      public void ResetPointProperties<T> (List<T> Points) 
      { 
          foreach (dynamic point in Points)
          {
              point.Reset();
          }
      }
      

      如果可能,最好的解决方案是使用接口和通用约束。接下来是强制转换,然后做一些事情(例如,在类来自某个外部 dll 并且您无法控制它的情况下)。通常不建议使用反射和动态,因为它们很慢,而且几乎不可能进行单元测试。

      但有时使用反射和动态可能会在一些复杂的场景中解决相当长的时间。

      假设您在数据库中有 40 个模型,并且这 40 个模型中的每一个模型都有 3 个视图模型,并且您想以某种方法映射它们......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-18
        • 1970-01-01
        • 1970-01-01
        • 2017-01-22
        • 2010-09-16
        • 2013-08-17
        相关资源
        最近更新 更多