Welcome

首页 / 软件开发 / .NET编程技术 / 扩展方法和静态方法使用相同签名而带来的莫名其妙的错误

扩展方法和静态方法使用相同签名而带来的莫名其妙的错误2010-12-29 博客园 Bruce很久以前我写过一篇文章简单介绍扩展方法、接口和继承带来的有趣现象,而这篇文章就没那么“有趣”了,介绍由于扩展方法和静态方法命名的冲突引起一个莫名其妙的错误,由于这个莫名其妙的错误暂时使我不能以较好的方式实现我的一些想法,特郁闷的是我觉得不应该是上的错误,而且本来就不应该有这种错误,所以称之为莫名其妙的错误。

错误描述:Member "...TestMethod()" cannot be accessed with an instance reference; qualify it with a type name instead

是编译错误,其大概意思是实例不能访问TestMethod这个方法,请用类型名字代替。即编译器认为我是用实例访问一个静态方法,而实际上该实例是访问扩展方法,只是这个类的静态方法和扩展方法名字都是叫TestMethod。

有人可能会问:你没事干嘛在静态方法和扩展方法中都用同一个名字?

这一切从我开始为Expression写扩展方法说起。这里给段小插曲——近来写了不少与Expression有关的扩展和封装,以挖掘Expression更多的应用。写多了,开始厌倦了这种静态方法:

Expression.Constant(...) ;
Expression.Property (...);
Expression.Lambda(...);

如果在实际中想构建以下Lambda表达式,

Expression<Func<Foo, bool>> expr = c => c.属性==1;

那么参数、属性、lambda、二元表达式等等是不可避免的,如下伪代码:

... Expression.Parameter (typeof(Foo), "c");
... Expression.Property (...);
... Expression.Equal(...);
... Expression.Lambda(...);
...

如果要构建的表达式比较长的话,我觉得以上代码对于阅读者来说,当他想看到各表达式之间的联系是有点困难的。

于是我试图对常用表达式进行扩展来达到类似代码风格:

ParameterExpression c= typeof(Foo).AsParameter("c");
Expression<Func<Foo, bool>> expr = c.Lambda(c.Property("属性").Equal(1));

因为这种写法跟它本身要实现的目标基本上是比较接近,如: c.Lambda(c.Property("属性").Equal(1)) 是实现 c => c.属性==1

我感觉这种写法更整洁,语言也清晰,所以立马付诸行动,结果碰了一鼻子灰。

原因是无法调用这个扩展方法:

public static MemberExpression Property(this Expression expression, string propertyName)

Why?

因为 Expression 里有这一个 静态方法:

public static MemberExpression Property(Expression expression, string propertyName)

这个原因让我哭笑不得,因为我认为编译器应该可以区分两者,如:

Expression expr = ...;
expr.Property("属性"); //使用扩展方法

Expression.Property("属性"); //使用静态方法