c#泛型中的通配符等价
本文关键字:通配符 泛型 | 更新日期: 2023-09-27 18:05:15
假设我有一个泛型类,如下所示:
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#中找出一个等效的,但没有成功。什么好主意吗?
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[]
作为参数