c#泛型中的通配符等价

本文关键字:通配符 泛型 | 更新日期: 2023-09-27 18:05:15

假设我有一个泛型类,如下所示:

public class GeneralPropertyMap<T>
{
}

在其他类中,我有一个方法,它接受GeneralPropertyMap<T>的数组。在Java中,为了接收包含任意类型GeneralPropertyMap的数组,该方法看起来像这样:

private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}

我们使用通配符,以便稍后我们可以调用TakeGeneralPropertyMap传递一堆GeneralPropertyMapT的任何类型,像这样:

GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);

我试着在c#中找出一个等效的,但没有成功。什么好主意吗?

c#泛型中的通配符等价

c#中的泛型比Java中的泛型提供更强的保证。因此,要在c#中做你想做的事情,你必须让GeneralPropertyMap<T>类从该类(或接口)的非泛型版本继承。

public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
    // Only you can implement it:
    internal GeneralPropertyMap() { }
}

现在你可以这样做:

private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}

:

GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);

虽然,正如其他人注意到的,在c#中通配符没有确切的对应关系,但它们的一些用例可以用协方差/逆变性来覆盖。

public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so 
                                        // we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
                                                            // inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
    var maps = new List<IGeneralPropertyMap<Object>> {
        new GeneralPropertyMap<String>(),
        new GeneralPropertyMap<Regex>()
    };
    //And finally pass the array in.
    TakeGeneralPropertyMap<Object>(maps);

需要注意的是,你不能对值类型使用协方差,所以在编译时向列表中添加新的GeneralPropertyMap<int>()会失败。

cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'

如果您想约束GeneralPropertyMap可以包含的类型,这种方法可能比拥有类/接口的非泛型版本更方便。在这种情况下:

public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {} 

允许有:

var maps = new List<IGeneralPropertyMap<IMyType>> {
    new GeneralPropertyMap<A>(),
    new GeneralPropertyMap<B>() ,
    new GeneralPropertyMap<C>() 
};
TakeGeneralPropertyMap(maps);

在c#中没有直接对应的

在c#中,这通常是通过让泛型类实现非泛型接口或基类来实现的:

interface IPropertyMap
{
   // Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}

你可以传递一个数组:

IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);

实际上,您可以通过使用dynamic来接近通配符。如果你有一个非泛型超类,这也可以很好地工作。

例如:

public class A
{
  // ...
}
public class B<T> : A
{
  // ...
}
public class Program
{
  public static A MakeA() { return new A(); }
  public static A MakeB() { return new B<string>(); }
  public static void Visit<T>(B<T> b)
  {
    Console.WriteLine("This is B with type "+typeof(T).FullName);
  }
  public static void Visit(A a)
  {
    Console.WriteLine("This is A");
  }
  public static void Main()
  {
    A instA = MakeA();
    A instB = MakeB();
    // This calls the appropriate methods.
    Visit((dynamic)instA);
    Visit((dynamic)instB);
    // This calls Visit(A a) twice.
    Visit(instA);
    Visit(instB);
  }
}

GeneralPropertyMap (IGeneralPropertyMap)的成员中创建一个接口,然后将IGeneralPropertyMap[]作为参数