編輯:我提交的微軟的bug報告連接:: https://connect.microsoft.com/VisualStudio/feedback/details/614234/delegate-createdelegate-allows-binding-functions-with-enum-parameters-to-the-enum-base-type#details爲什麼Delegate.CreateDelegate允許無效轉換?
考慮下面的事情:
public static Int32 Test(Int16 @short)
{
return @short;
}
和調用代碼::
Func<Int16,Int32> test = Test; //valid method group conversion.
Func<Int16,StringComparison> test2 = Test; // doesn't compile, not valid method group conversion.
Func<Int16,StringComparison> test3 = test; // doesn't compile, invalid contra-variance.
Func<Int16,StringComparison> test4 = Delegate.CreateDelegate(typeof(Func<Int16,StringComparison>),test.Method) as Func<Int16,StringComparison>; // works fine.
爲什麼能Delegate.CreateDelegate做這個奇怪的轉換,沒有其他方式創建一個功能允許?更糟糕的是,一個比較合理的轉換說Int64
或Object
都失敗了。我意識到StringComparison
「延伸」Int32
,但我認爲這是更多的編譯器技巧,因爲枚舉的擴展Enum
類。
此外,此轉換也適用於DynamicMethod.CreateDelegate
。
編輯剛試過Nullable<Int32>
它不起作用,這是令人困惑的。我認爲唯一的「免費」轉換是將Enum
類型轉換爲其基礎類型,但爲什麼?
請注意,這不允許您將int實例方法(如GetHashCode)轉換爲採用枚舉類型的開放方法,這就是爲什麼我認爲這是一個錯誤,因爲行爲不一致。
編輯: 如果我們刪除test2和test3行,然後我們可以測試看到方法,委託和「非法」委託都按預期工作。
Console.WriteLine(Test(0)); // prints 0
Console.WriteLine(test(0)); // prints 0
Console.WriteLine(test4(0)); //prints CurrentCulture
編輯: 下面是這一點,我在大約10分鐘寫了一個非常大的弊端。這爲TEnum
創建了一個IEqualityComparer<T>
,通過基本上抓取它的基礎類型,然後包裝Equals和HashCode,並使用這個技巧/濫用將參數轉換爲TEnums而不是基礎類型。如果這是我想知道的錯誤,那麼我不會試圖依賴這種行爲。
class EnumComparer<TEnum> : EqualityComparer<TEnum> where TEnum : struct
{
static Func<TEnum, TEnum, bool> s_Equals;
static Func<TEnum, int> s_HashCode;
static EnumComparer<TEnum> s_default;
static EnumComparer()
{
if (!typeof(TEnum).IsEnum) throw new Exception("Not an enum type");
Type underlyingType = Enum.GetUnderlyingType(typeof(TEnum));
object equalityComparer = typeof(EqualityComparer<>).MakeGenericType(new[] { underlyingType }).GetProperty("Default").GetGetMethod().Invoke(null, null);
s_Equals = Delegate.CreateDelegate(typeof(Func<TEnum, TEnum, bool>), equalityComparer,equalityComparer.GetType().GetMethod("Equals", new[]{underlyingType,underlyingType})) as Func<TEnum,TEnum,bool>;
s_HashCode = Delegate.CreateDelegate(typeof(Func<TEnum, int>), equalityComparer, equalityComparer.GetType().GetMethod("GetHashCode", new[]{underlyingType})) as Func<TEnum, int>;
s_default = new EnumComparer<TEnum>();
}
public static new EnumComparer<TEnum> Default
{
get
{
return s_default;
}
}
public override bool Equals(TEnum x, TEnum y)
{
return s_Equals(x, y);
}
public override int GetHashCode(TEnum obj)
{
return s_HashCode(obj);
}
private EnumComparer()
{
}
}
也許下面的鏈接將很有用:http://stackoverflow.com/questions/2490828/createdelegate-with-unknown-types,http://kohari.org/2009/03/06/fast-late-bound- invocation-with-expression-trees /,http://www.west-wind.com/Weblog/posts/653034.aspx,http://social.msdn.microsoft.com/Forums/en-US/roboticsccr/thread/2e80a245-607e-4f15-93ad-1f74ae5406f1 – 2010-10-16 17:08:02
這裏很好Jon Skeet的帖子:http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx – 2010-10-16 17:15:25
當你使用這種方法時,你的任何關於Atum和Int之間的隱式轉換都沒有提及。他們也都在談論使用LGC編寫代碼,這種方法正在避免。 – 2010-10-16 17:21:18