次のようなジェネリッククラスがあるとしましょう。
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#のワイルドカードに正確に対応するものはありませんが、それらのユースケースのいくつかは 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);
_
C#にはこれに直接相当するものはありません。
C#では、これは多くの場合、ジェネリッククラスに非ジェネリックインターフェイスまたは基本クラスを実装させることによって行われます。
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
次に、これらの配列を渡すことができます。
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
GeneralPropertyMap
(IGeneralPropertyMap
)のメンバーからインターフェースを作成し、次にIGeneralPropertyMap[]
引数として。
実際には、動的を使用することでワイルドカードにかなり近づくことができます。これは、ジェネリックでないスーパークラスがある場合にもうまく機能します。
例えば:
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#ドキュメント ここ で説明されています。