我想知道如何做这样的工作:
using System; class Program { static void Main() { var f = new IFoo { Foo = "foo", Print = () => Console.WriteLine(Foo) }; } } interface IFoo { String Foo { get; set; } void Print(); }
创建的匿名类型看起来像这样:
internal sealed class <>f__AnonymousType0<j__TPar> : IFoo { readonly j__TPar i__Field; public <>f__AnonymousType0( j__TPar Foo) { this. i__Field = Foo; } public j__TPar Foo { get { return this. i__Field; } } public void Print() { Console.WriteLine(this.Foo); } }
是否有任何理由让编译器无法做到这样的事情?即使对于采用参数的非void方法或方法,编译器也应该能够从接口声明中推断出类型.
免责声明:虽然我确实认识到目前这不可行,但在这种情况下简单地创建一个具体的类更有意义,我对此的理论方面更感兴趣.
重载成员,索引器和显式接口实现会有一些问题.
但是,您可以以允许您解决这些问题的方式定义语法.
有趣的是,通过编写库,您可以非常接近C#3.0所需的内容.基本上,你可以这样做:
Create( new { Foo = "foo", Print = (Action)(() => Console.WriteLine(Foo)) } );
这与你想要的非常接近.主要区别是调用"Create"而不是"new"关键字,以及需要指定委托类型的事实.
"创建"的声明如下所示:
T Create(object o) { //... }
然后,它将使用Reflection.Emit在运行时动态生成接口实现.
但是,这种语法确实存在显式接口实现和重载成员的问题,在不更改编译器的情况下无法解决.
另一种方法是使用集合初始值设定项而不是匿名类型.这看起来像这样:
Create { new Members{ {"Print", ((IFoo @this)=>Console.WriteLine(Foo))}, {"Foo", "foo"} } }
这将使您能够:
通过为字符串参数指定类似"IEnumerable.Current"的内容来处理显式接口实现.
定义Members.Add,这样您就不需要在初始化程序中指定委托类型.
你需要做一些事情来实现这个:
为C#类型名称编写一个小解析器.这只需要".","[]","<>",ID和原始类型名称,所以你可能会在几个小时内完成
实现缓存,以便您只为每个唯一的接口生成一个类
实现Reflection.Emit代码gen.这最多可能需要2天左右.
它需要c#4,但开源框架即兴接口可以在内部使用DLR代理来伪装这个开箱即用.虽然不如你提出的改变存在,但表现还是不错的.
using ImpromptuInterface.Dynamic;
...
var f = ImpromptuGet.Create(new{ Foo = "foo", Print = ReturnVoid.Arguments(() => Console.WriteLine(Foo)) });