使用泛型类型和表达式选择扩展方法

时间:2013-09-03 07:54:37

标签: c# generics extension-methods overloading

我有一些扩展方法,它们使用 Expression 参数来引入属性成员并对其进行操作,并且对于成员为 IEnumerable<的特定情况,我有一个重载。 > 即可。但是,从泛型类( for r4 )中调用时,它似乎与预期的方法重载不匹配。在课外,选择了正确的方法。

这里发生了什么?这有用还是我需要找到新的方法?

(这是在C#5中)

public class Test
{
    public void MyTest()
    {
        // returns "Object"
        var r1 = new MyClass<object>().Ext(a => a.Content);

        // returns "Enumerable"
        var r2 = new MyClass<IEnumerable<object>>().Ext(a => a.Content);

        // returns "Object"
        var r3 = new MyClass<object>().TestExt();

        // returns "Object" (I was expecting "Enumerable")
        var r4 = new MyClass<IEnumerable<object>>().TestExt();

        // returns "Enumerable"
        var r5 = new MyClass<int>().TestExt2();
    }
}

public class MyClass<T>
{
    public T Content { get; set; }

    public IEnumerable<object> OtherContent { get; set; }

    public string TestExt()
    {
        return this.Ext(a => a.Content);
    }

    public string TestExt2()
    {
        return this.Ext(a => a.OtherContent);
    }
}

public static class MyExtensions
{
    public static string Ext<T>(this T obj, Expression<Func<T, IEnumerable<object>>> memberExpression)
    {
        return "Enumerable";
    }

    public static string Ext<T>(this T obj, Expression<Func<T, object>> memberExpression)
    {
        return "Object";
    }
}

1 个答案:

答案 0 :(得分:4)

泛型不是动态类型。在编译时冻结要调用的重载。当程序稍后运行时,即使变量碰巧保持更具体的运行时类型,这也无关紧要,因为在编译时修复了重载。

你的方法:

public string TestExt()
{
    return this.Ext(a => a.Content);
}

必须在编译时绑定到Ext的一个特定重载。由于我们所知道的T a.ContentMyClass<T>中的object类型是可转换为TestExt,因此实际上只有一个重载可供选择,所以这对编译器来说很容易。

从那时起,Ext方法主体被硬编码为调用static void Main() { IEnumerable<object> e = new List<object>(); var r = Generic(e); } static string Generic<T>(T x) { return Overloaded(x); } static string Overloaded(IEnumerable<object> x) { return "Enumerable"; } static string Overloaded(object x) { return "Object"; } 的特定重载。


编辑:这是一个更简单的例子:

r

正如您现在所理解的那样,"Object"变为T

(如果以某种方式约束where T : IEnumerable<object>,例如==,事情会有所不同。

对于运营商来说也是如此。例如,==运算符被重载,因为它以一种方式对一般引用类型起作用,而在另一种方式中对于字符串起作用。因此,在下面的示例中,运算符Overloaded从以前开始扮演static void Main() { string str1 = "abc"; string str2 = "a"; str2 += "bc"; // makes sure this is a new instance of "abc" bool b1 = str1 == str2; // true bool b2 = Generic(str1, str2); // false } static bool Generic<T>(T x, T y) where T : class { return x == y; } 角色:

b2

其中false变为{{1}}。