如果您有一個通用類型的參數,可能會或可能不會執行IFoo
,它可能將as
轉儲到IFoo
類型的存儲位置;如果你這樣做了,你可以將它傳遞給任何需要IFoo
的方法,以及任何需要泛型參數限制爲IFoo
的方法,但是如果你這樣做的話你將失去所有泛型類型信息 - 參數將被傳遞如IFoo
。除此之外,這意味着如果你的原始對象是一個結構,它將被裝箱。
如果你想測試一個泛型參數類型是否實現IFoo
並調用了一個通用的約束IFoo
如果這樣做,同時保持原有的泛型類型(這可能如果類型是一個結構是有用的方法,以及可能是必要的,如果類型被傳遞給既有IFoo
和IBar
約束的泛型方法,也有可能想要傳遞的東西不共享任何單個常見超類型),則有必要使用Reflection。
例如,假設一個人想有一個方法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
是否執行。這個非常重要。否則,如果MaybeDispose
與它舉行了參照Stream
Object
類型的參數調用,它將確定it
實施IDisposable
,因此嘗試創建一個ClassDisposer<Object>
,轟然因爲Object
沒有實現IDisposable
。
_NEVER_在泛型類中放置一個泛型方法,其中方法的泛型類型參數與類的名稱相同,只是要求麻煩。 – 2013-04-26 03:06:50
@Jeff - 那實際上是一個錯字。 。我已經更新了這個問題 – leora 2013-04-26 03:22:42
爲什麼只有某個類實現了IFilterable?爲什麼不是所有的類都使用空實現進行篩選? – 2013-05-01 07:53:45