C#泛型中的通配符等价物

时间:2013-03-22 16:11:56

标签: c# .net arrays generics wildcard

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

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#中的等价物并没有成功。有什么想法吗?

5 个答案:

答案 0 :(得分:18)

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

答案 1 :(得分: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);

答案 2 :(得分:3)

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

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

interface IPropertyMap
{
   // Shared properties
}

public class GeneralPropertyMap<T> : IPropertyMap
{
}

然后你可以传递这些数组:

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

TakePropertyMap(maps);

答案 3 :(得分:0)

GeneralPropertyMapIGeneralPropertyMap)的成员创建一个界面,然后以IGeneralPropertyMap[]作为参数。

答案 4 :(得分:0)

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

例如:

<param name="columns" type="int" min="3" max="100" _gui-text="Cols">6</param>
<param name="ratio" type="float" min="0.5" max="1" precision="3" appearance="full" _gui-text="ratio">1.0</param>

这是如何工作的,请参见C#文档here