是否可以在函数体内使用通用机制?
例如
if (!(someClass is IClass<T, G> where T : someInterface, G : anotherInterface))
{
return;
}
或像这样进行铸造:
var v = (IClass <T, G> where T : someInterface, G: anotherInterface)something;
对于第一个示例,是的 - 您只需要指定类型:
if (!(someClass is IClass<ISomeInterface, IAnotherInterface>))
{
return;
}
另一个大同小异:
var v = (IClass <ISomeInterface, IAnotherInterface>)something;
虽然它可能更好用as
var v = something as IClass <ISomeInterface, IAnotherInterface>;
if(v != null)
{
// Do something.
}
上面的第二行很重要 - 通过使用as
代替直接强制转换,InvalidCastException
如果失败,您将不会得到,但v
如果使用强制转换失败,则会为空as
。如果您的施法尝试无效,此技术可让您更好地控制失败。(考虑一下为什么转换会无效:如果这代表一种情况,您知道更久知道世界是什么样子,那么InvalidCastException
这可能是正确的方法。如果对象不是接口的实例是合理的,那么as
您的朋友。)
你可以这样做,但你必须确保你的界面是协变的:
interface IClass<out T, out S>
{
// Methods that can return a T or S but not accept one as input
}
通过将类型参数标记为out
,您基本上是在说“我只会从这个接口中得到 aT
或 a ”。例如,因为您只能从中取出 a,但仅仅是因为您可以将 a放入列表中并取出一个。S
IEnumerable<out T>
T
List<T>
T
已经这样定义了你的接口, anIClass<string, string>
是an IClass<object, object>
:你知道你IClass<string, string>
只会给你 a string
,但是既然 astring
是 anobject
那么那很好,如果你将它分配给 anIClass<object, object>
你知道它只会给你一个object
.
(如果您的接口允许您将 a或 an放入某物,则您不能这样做。如果是这种情况,并且您将您分配给 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<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!
}