Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>
. In Java, in order to take in an array that contains any type of GeneralPropertyMap
the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap
passing a bunch of GeneralPropertyMap
with any type for T
each, like this:
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);
I'm trying to figure out an equivalent in C# with no success. Any ideas?
Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T>
class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);
While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with 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);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>()
to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap
can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);
There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
从GeneralPropertyMap
( IGeneralPropertyMap
) 的成员创建一个接口,然后将IGeneralPropertyMap[]
作为参数。
Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
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);
}
}
How this works is explained in the C# documentation here .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.