C# 编译时类型检查

C# 编译时类型检查,c#,generics,collections,parameters,C#,Generics,Collections,Parameters,想象一个泛型类B public class B<T> : IB { public void Foo(object parameter) { var param = (T)parameter; //... } } 稍后,我想在类A上执行一些方法,比如foo,它将获取T类型的对象集合,其中T是构造函数中传递的B实例的泛型。所以这些类型必须匹配 public void foo(IEnumerable<object> param) {

想象一个泛型类B

public class B<T> : IB
{
   public void Foo(object parameter)
   {
      var param = (T)parameter;
      //...
   }
}
稍后,我想在类A上执行一些方法,比如foo,它将获取
T
类型的对象集合,其中
T
是构造函数中传递的
B
实例的泛型。所以这些类型必须匹配

public void foo(IEnumerable<object> param)
{
   for (int i = 0; i < collectionOfBs.Count(); i++)
   {
     collectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
   }
}
public void foo(IEnumerable参数)
{
对于(int i=0;i
现在我正在传递一个
IEnumerable
并将其转换为foo内部的
T
类型,这将起作用,但我想知道是否可以在编译时进行此类型检查

有没有可能的想法?
谢谢

您可以使用提供参数类型的通用方法来尝试此操作

它不能确保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));
      }
    }
考虑

这里的问题是,任何错误的匹配参数类型都可能被传递

例如,对于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));
    }
  }
}
公共接口IB
{
void-Foo(T参数);
}
B级:IB
{
公共void Foo(T参数)
{
var param=参数;
WriteLine(“参数类型:”+param.GetType().Name);
}
}
公共A类
{
私人收藏;
公共A(IEnumerable CollectionFBS)
{
CollectionOfBs=CollectionOfBs;
}
公共void Foo(IEnumerable参数)
{
if(param.Count()

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

如果需要一致的泛型类型检查,则需要一致地应用泛型。目前,您使用的是一种折衷方法:
B
是通用的,但
IB
不是。然后您有一个非泛型类
a
,该类耦合到非泛型接口
IB
,但您需要对
T
进行编译时类型检查,而
a
IB
对此一无所知(只是在内部将其强制转换为
T
)。这有点问题

从类/接口的使用情况来看,显然您不希望在
A
中使用混合的
IB
实现,因此您可以做的是在所有类型上一致地应用泛型类型参数
t

public 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 });
    }
}
公共B类:IB
{
公共void Foo(T参数)
{
var param=参数;
//...
}
}
公共A类
{
公共A(IEnumerable collectionOfBs){}
公共void foo(IEnumerable参数)
{
collectionOfBs.Zip(param,(b,t)=>{b.Foo(t);返回0});
}
}

请注意,我将您的方法替换为
for
ElementAt
by
Enumerable.Zip

就您所写的内容所知,IB的具体类可能根本就没有这样的方法可以使用。您还可以使您的
IB
接口通用。
IB
对类型
T
一无所知。只有类
B
知道
T
是什么。我能想到的一个选择是将方法
foo
放在类
B
insteadmagine having
var b1=new B();var b2=新的B()
然后创建一个
A
的实例,如下所示
vara=newa(newib[]{b1,b2})。在这种情况下,“在构造函数中传递的B实例的泛型类型”是什么?更不用说
a=newa(newib[]{b1,b2,c})的情况
c
c
类型的对象,它也实现了
IB
@AhmedAbdelhameed。可执行项必须看起来像{5,“bar}。这回答了你的问题吗?@SimplyGed我不认为这是一个选项,
foo
迭代
IB
的所有实例,并将参数传递给它们。但是在这里,A的实例将决定类型
t
,因此
B
的所有实例也必须具有相同的泛型
t
?(见艾哈迈德的评论和我的回答)看起来很有希望,我稍后会检查,现在没有时间;)
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));
    }
  }
}
public 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 });
    }
}