C# 4.0,即时方法?

5

随着类似鸭子类型的引入,我希望能够在扩展方法之外动态地组合对象方法。有人知道这是否可能吗?我知道微软担心动态地组合框架,但他们似乎正在试水。

更新:感谢Pavel的澄清。例如,假设我从LINQ返回一个新的动态对象,并希望动态地添加一些方法。


你是指运行时代码生成吗?还是指像JavaScript一样动态地向对象添加方法? - Pavel Minaev
看起来你可以用表达式树来完成,但这真是个让人抓狂的事。 - Trent
3个回答

12

根据更新后的答案,您实际上并不需要"动态方法",更多的是需要"动态对象"——这样您可以在运行时添加新属性和方法。如果是这样的话,在.NET 4.0中,您可以使用ExpandoObjectdynamic结合使用:

dynamic foo = new ExpandoObject();
foo.Bar = 123; // creates a new property on the fly
int x = foo.Bar; // 123

// add a new method (well, a delegate property, but it's callable as method)
foo.Baz = (Func<int, int, int>)
    delegate(int x, int y)
    {
        return x + y;
    };

foo.Baz(1, 2); // 3

你也可以使用表达式树来创建“动态方法”,一旦你获得了这样一个方法的委托,你还可以在 ExpandoObject 上创建一个可调用的类似方法的属性。
对于 LINQ 查询,不幸的是,你不能使用对象初始化器来创建 ExpandoObject。在最简单的情况下,以下代码将无法编译:
var foo =  new ExpandoObject { Bar = 123; }

原因是在这种情况下,Bar会被静态地作为ExpandoObject的属性查找。你需要将接收器设置为dynamic才能启用此功能,在对象初始化程序中无法实现。作为在LINQ中使用的解决方法,考虑使用以下帮助扩展方法:
public static dynamic With(this ExpandoObject o, Action<dynamic> init)
{
     init(o);
     return o;
}

现在您可以这样使用它:

from x in xs
select new ExpandoObject().With(o => {
    o.Foo = x;
    o.Bar = (Func<int, int>)delegate(int y) { return x + y; };
});

不错!如果我使用LINQ创建了一个动态对象(返回指定属性),那么它是可以添加方法的ExpandoObject吗? - Trent
匿名类型(通过在 new 后未指定类的 new { ... } 创建)不是可扩展类型。有关详细信息,请查看编辑后的答案。 - Pavel Minaev
干得不错。只需要一些语法修正就能编译通过了。将 Action<> 替换为 Func<>,并且在动态属性/方法创建后需要用 ';' 代替 ','。 - Trent
@Trent,谢谢你指出的错误,我已经更新了代码进行修复。 - Pavel Minaev
+1 个明确而有用的答案。这是在雨天期待和尝试的东西 :) - Abel

2

1
这仅适用于静态方法。请参阅此帖子:http://www.justnbusiness.com/post/2009/08/02/LambdaExpressionCompileToMethod-e280a6-not-nearly-as-cool-as-I-had-hoped.aspx - Sam Harwell

1

借助 DynamicMethod 和/或 MethodBuilder 已经可以实现这一点。虽然它已经存在一段时间了,但不确定是否算得上 "担心",因为在大多数情况下需要动态程序集 (尽管可以在没有动态程序集的情况下使用 DynamicMethod)。


当我说担心时,我的意思是这个:http://blogs.msdn.com/csharpfaq/archive/2004/03/09/86979.aspx。我本来希望避免使用反射,但还是感谢你的提示。 - Trent
抱歉,这句话有点双关语。正如你已经发现的那样,不需要使用反射。Pavel写下的答案很好! - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接