関数本体内で汎用メカニズムを使用することは可能ですか?
たとえば
if (!(someClass is IClass<T, G> where T : someInterface, G : anotherInterface))
{
return;
}
または、次のようにキャストします。
var v = (IClass <T, G> where T : someInterface, G: anotherInterface)something;
これを行うことができますが、インターフェイスが共変であることを確認する必要があります。
interface IClass<out T, out S>
{
// Methods that can return a T or S but not accept one as input
}
型パラメーターを としてマークすることで、基本的に「このインターフェイスからは aまたはout
a のみを取得する」と言っています。たとえば、リストから aしか取得できないのは、 a をリストに入れることも 1 つを取得することもできるからです。T
S
IEnumerable<out T>
T
List<T>
T
インターフェースをそのように定義すると、 anIClass<string, string>
はanです。あなたは、あなたが a だけを与えることIClass<object, object>
を知っていますが、 aは an であるので、それは問題ありません。IClass<string, string>
string
string
object
IClass<object, object>
object
(インターフェイスで aまたは anを何かに入れることができる場合、これを行うことはできません。この場合、 yourを anに割り当てた場合、an をそれに入れようとすると失敗します。実際には a のみを受け入れます。)T
S
IClass<string, string>
IClass<object, object>
int
string
これでできることは
if (!(something is IClass<object, object>))
{
return;
}
また
var v = (IClass<object, object>)something;
something
が実際にを実装するオブジェクトである場合、両方とも機能しますIClass<string, string>
。
最初の例では、はい - タイプを指定するだけです:
if (!(someClass is IClass<ISomeInterface, IAnotherInterface>))
{
return;
}
もう1つはほとんど同じです。
var v = (IClass <ISomeInterface, IAnotherInterface>)something;
おそらく使用する方が良いですがas
var v = something as IClass <ISomeInterface, IAnotherInterface>;
if(v != null)
{
// Do something.
}
上記の 2 行目は重要as
です。直接キャストの代わりに使用すると、失敗したInvalidCastException
場合は取得されませんが、v
使用したキャストが失敗した場合は null になりas
ます。この手法を使用すると、キャストの試行が無効な場合に、失敗をもう少し制御できます。(変換が無効になる理由を考えてみてください。それが、世界がどのように見えるかをより長く知っている状況を表している場合InvalidCastException
は、おそらく正しいアプローチです。オブジェクトがインターフェイスのインスタンスではないas
ことが合理的である場合は、友達。)
あなたはこれを試すことができます:
if (!(someClass is IClass<someInterface, anotherInterface>)
{
return;
}
またはリフレクション経由:
var t = someClass.GetType()
Type[] typeParameters = t.GetGenericArguments();
if (!typeParameters[0].IsSubclassOf(typeof(someInterface)) ||
!typeParameters[1].IsSubclassOf(typeof(anotherInterface)))
{
return;
}
where
ジェネリック メソッド自体に制約が適用されます。目的のタイプを問題なく使用できます。
余談ですが、 falseをチェックしないでください。長い目で見ると混乱を招きます。
if (someClass is IClass<someInterface, anotherInterface>)
{
// your code
}
// else { return; } // no longer needed!
コードを展開してジェネリック メソッドに含めると、次のようになります。
void myMethod<T, U>()
where T : someInterface
where U : anotherInterface
{
if (someClass is IClass<T, U>)
{
// your code
}
// else { return; } // no longer needed!
}