28

假设我有一个通用类,如下所示:

public class GeneralPropertyMap<T>
{
}

在其他一些类中,我有一个方法,它接受一个数组GeneralPropertyMap<T>。在 Java 中,为了接收包含任何类型GeneralPropertyMap方法的数组,如下所示:

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

我们使用通配符,以便稍后我们可以调用为每个TakeGeneralPropertyMap传递一堆GeneralPropertyMap任何类型的T,如下所示:

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# 中的等价物,但没有成功。有任何想法吗?

4

5 回答 5

22

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);
于 2013-03-22T16:18:28.433 回答
9

虽然,正如其他人所指出的,在 c# 中没有与通配符完全对应,但它们的一些用例可以用covariance/contravariance覆盖。

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);
于 2013-03-22T16:36:40.233 回答
5

在 C# 中没有直接的等价物。

在 C# 中,这通常通过让泛型类实现非泛型接口或基类来完成:

interface IPropertyMap
{
   // Shared properties
}

public class GeneralPropertyMap<T> : IPropertyMap
{
}

然后,您可以传递这些数组:

IPropertyMap[] maps = new IPropertyMap[3];
// ...

TakePropertyMap(maps);
于 2013-03-22T16:14:50.657 回答
0

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

于 2013-03-22T16:19:27.397 回答
0

实际上,您可以通过使用动态来非常接近通配符。如果您有一个非泛型超类,这也很有效。

例如:

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);
  }
}

此处的 C# 文档解释了其工作原理。

于 2019-06-28T09:08:24.640 回答