编辑:我提交的微软的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