编译时间类型检查

时间:2019-10-10 06:18:52

标签: c# generics collections parameters

想象一个通用的B类

public class B<T> : IB
{
   public void Foo(object parameter)
   {
      var param = (T)parameter;
      //...
   }
}

还有一个类A,它是通过其构造函数传递的B的集合。请注意,我在此处使用接口IB作为输入。

public class A
{
   public A(IEnumerable<IB> collectionOfBs) {}

}

有时候,我想在类A上执行一些方法,比方说foo,它将接受T类型的对象的集合,其中T是{实例的通用类型{1}}传入构造函数。所以这些类型必须匹配。

B

现在我在foo内部传递了一个public void foo(IEnumerable<object> param) { for (int i = 0; i < collectionOfBs.Count(); i++) { collectionOfBs.ElementAt(i).Foo(param.ElementAt(i)); } } 并强制转换为类型IEnumerable<object>,这可以工作,但是我想知道是否可以在编译时检查此类型吗?

有可能吗? 谢谢

2 个答案:

答案 0 :(得分:0)

对于提供的参数类型,您可以使用通用方法进行尝试。

由于您有一个非通用的接口,因此不能确保TParam和T相同,但是,据我对问题的首次研究表明,它是您所能做到的最好的方法...

因为在C#中没有钻石运算符允许对开放类型进行真正的通用多态。

    public interface IB
    {
      void Foo<TParam>(TParam parameter);
    }

    public class B<T> : IB
    {
      public void Foo<TParam>(TParam parameter)
      {
        var param = parameter;
        Console.WriteLine("param type: " + param.GetType().Name);
      }
    }

    public class A
    {
      private IEnumerable<IB> CollectionOfBs;

      public A(IEnumerable<IB> collectionOfBs)
      {
        CollectionOfBs = collectionOfBs;
      }

      public void Foo(IEnumerable<object> param)
      {
        if ( param.Count() < CollectionOfBs.Count() )
          throw new ArgumentException();
        for ( int i = 0; i < CollectionOfBs.Count(); i++ )
          CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
      }
    }

测试方法

    static void Test()
    {
      var listInstances = new List<IB> { new B<int>(), new B<double>(), new B<string>() };

      var container = new A(listInstances);

      var listParams = new List<object> { 2, 4.3, "test" };

      container.Foo(listParams);
    }

输出

param type: Int32
param type: Double
param type: String

注意事项

这里的问题是可以传递任何错误的匹配参数类型。

例如,使用Test(),您可以使用double而不是第一个整数,并且可以使用:您在Int32实例上获得了Double ...

param type: Double
param type: Double
param type: String

有了菱形运算符<>,您将能够使用通用接口并在封闭的构造类型列表上进行解析...,您的设计将具有更好的气味:

public interface IB<T>
{
  void Foo(T parameter);
}

public class B<T> : IB<T>
{
  public void Foo(T parameter)

  {
    var param = parameter;
    Console.WriteLine("param type: " + param.GetType().Name);
  }
}

public class A
{
  private IEnumerable<IB<>> CollectionOfBs;

  public A(IEnumerable<IB<>> collectionOfBs)
  {
    CollectionOfBs = collectionOfBs;
  }

  public void Foo(IEnumerable<object> param)
  {
    if ( param.Count() < CollectionOfBs.Count() )
      throw new ArgumentException();
    for ( int i = 0; i < CollectionOfBs.Count(); i++ )
    {
      CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
    }
  }
}

因此,任何错误匹配的参数类型都会在运行时引发异常。

答案 1 :(得分:-1)

要进行一致的泛型类型检查时,需要一致地应用泛型。当前,您正在使用半途而废的方法:B<T>是通用的,而IB不是。然后,您有一个非泛型类A,该类耦合到非泛型接口IB,但是您想对T进行编译时类型检查,两者都{{1} }和A一无所知(仅在内部将其强制转换为IB)。这有点问题。

从类/接口的用法看来,您似乎不希望在T中使用混合的IB实现,因此,您可以做的是一致地应用通用类型参数{{1 }}上的所有类型:

A

请注意,我用Tpublic class B<T> : IB<T> { public void Foo(T parameter) { var param = parameter; //... } } public class A<T> { public A(IEnumerable<IB<T>> collectionOfBs) {} public void foo(IEnumerable<T> param) { collectionOfBs.Zip(param, (b, t) => { b.Foo(t); return 0 }); } } for替换了您的方法。