如果您有一个可能实现也可能不实现的泛型类型参数,则IFoo
可以将as
其强制转换为 type 的存储位置IFoo
;如果你这样做,你可以将它传递给任何需要一个 的方法IFoo
,以及任何需要一个泛型参数约束到的方法IFoo
,但是如果你这样做,你将丢失所有泛型类型信息——参数将作为类型传递IFoo
. 除此之外,这意味着如果您的原始对象是一个结构,它将被装箱。
如果您希望测试泛型参数类型是否实现IFoo
并调用一个采用泛型约束的方法IFoo
,同时保持原始泛型类型(如果类型是结构,这可能很有用,如果类型被传递给一个具有IFoo
和IBar
约束的泛型方法,并且可能想要传递的东西不共享任何单一的公共超类型),则有必要使用反射。
例如,假设一个人想要一个方法Zap
,它接受一个泛型参数,如果它实现了就ref
调用它,然后清除它。如果参数是类类型,则应将空测试作为原子操作执行,并清除参数。Dispose
IDisposable
IDisposable
public static class MaybeDisposer
{
static class ClassDisposer<T> where T : class,IDisposable
{
public static void Zap(ref T it)
{
T old_it = System.Threading.Interlocked.Exchange(ref it, null);
if (old_it != null)
{
Console.WriteLine("Disposing class {0}", typeof(T));
old_it.Dispose();
}
else
Console.WriteLine("Class ref {0} already null", typeof(T));
}
}
static class StructDisposer<T> where T : struct,IDisposable
{
public static void Zap(ref T it)
{
Console.WriteLine("Disposing struct {0}", typeof(T));
it.Dispose();
it = default(T);
}
}
static class nonDisposer<T>
{
public static void Zap(ref T it)
{
Console.WriteLine("Type {0} is not disposable", typeof(T));
it = default(T);
}
}
class findDisposer<T>
{
public static ActByRef<T> Zap = InitZap;
public static void InitZap(ref T it)
{
Type[] types = {typeof(T)};
Type t;
if (!(typeof(IDisposable).IsAssignableFrom(typeof(T))))
t = typeof(MaybeDisposer.nonDisposer<>).MakeGenericType(types);
else if (typeof(T).IsValueType)
t = typeof(MaybeDisposer.StructDisposer<>).MakeGenericType(types);
else
t = typeof(MaybeDisposer.ClassDisposer<>).MakeGenericType(types);
Console.WriteLine("Assigning disposer {0}", t);
Zap = (ActByRef<T>)Delegate.CreateDelegate(typeof(ActByRef<T>), t, "Zap");
Zap(ref it);
}
}
public static void Zap<T>(ref T it)
{
findDisposer<T>.Zap(ref it);
}
}
第一次使用任何类型调用代码时T
,它将确定可以为该参数生成哪种泛型静态类,并使用反射创建一个委托来调用该泛型类的静态方法。具有相同类型的后续调用T
将使用缓存的委托。尽管反射可能有点慢,但对于任何类型,它只需要使用一次T
。MaybeDisposer.Zap<T>(ref T it)
所有具有相同类型的后续调用T
将直接通过委托分派,因此将快速执行。
请注意,MakeGenericType
如果给定的泛型类型参数不满足给定的开放泛型类的约束,则调用将引发异常(例如,如果T
是类或未实现IDisposable
,则尝试创建泛型类型StructDisposer<T>
将引发异常) ; 此类测试发生在运行时,编译器不会对其进行验证,因此您可以使用运行时检查来查看类型是否满足适当的约束。请注意,代码不测试是否it
实现IDisposable
,而是测试是否T
实现。这个非常重要。否则,如果使用包含对a 的引用MaybeDispose
的类型参数调用,它将确定已实现并因此尝试创建一个Object
Stream
it
IDisposable
ClassDisposer<Object>
Object
,因为没有实现而崩溃IDisposable
。