Can a C# anonymous class implement an interface?
是否可以让匿名类型实现接口?我有一段代码想要工作,但不知道该怎么做。
我有几个答案要么说不,要么创建一个实现接口的类来构造新的实例。这不太理想,但我想知道是否有一种机制可以在接口的顶部创建一个瘦的动态类,从而简化这个过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public interface DummyInterface { string A { get; } string B { get; } } public class DummySource { public string A { get; set; } public string C { get; set; } public string D { get; set; } } public class Test { public void WillThisWork() { var source = new DummySource[0]; var values = from value in source select new { A = value.A, B = value.C +"_" + value.D }; DoSomethingWithDummyInterface(values); } public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values) { foreach (var value in values) { Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B); } } } |
我发现了一篇描述一种方法的动态接口包装文章。这是最好的方法吗?
不,匿名类型不能实现接口。从C编程指南:
Anonymous types are class types that consist of one or more public read-only properties. No other kinds of class members such as methods or events are allowed. An anonymous type cannot be cast to any interface or type except for object.
虽然这可能是一个2年前的问题,虽然线程中的答案都是正确的,但我还是忍不住要告诉您,事实上,匿名类实现接口是可能的,尽管实现接口需要一些创造性的欺骗。
早在2008年,我就为当时的雇主编写了一个定制的LINQ提供者,在某一点上,我需要能够将"我的"匿名类与其他匿名类区分开来,这意味着让它们实现一个接口,我可以使用该接口对它们进行类型检查。我们解决这个问题的方法是使用方面(我们使用Postshap),直接在IL中添加接口实现。因此,实际上,让匿名类实现接口是可行的,您只需要稍微弯曲规则就可以实现。
将匿名类型强制转换为接口已经有一段时间了,但不幸的是,当前的实现强制您实现该接口。
围绕它的最佳解决方案是使用某种类型的动态代理来为您创建实现。使用优秀的临福项目,你可以取代
1 2 3 4 5 |
具有
1 2 3 4 5 |
匿名类型可以通过动态代理实现接口。
我在Github上写了一个扩展方法和一篇博客文章http://wblo.gs/fee来支持这个场景。
方法可以这样使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Program { static void Main(string[] args) { var developer = new { Name ="Jason Bowers" }; PrintDeveloperName(developer.DuckCast<IDeveloper>()); Console.ReadKey(); } private static void PrintDeveloperName(IDeveloper developer) { Console.WriteLine(developer.Name); } } public interface IDeveloper { string Name { get; } } |
不;除了具有一些属性外,不能使匿名类型执行任何操作。您需要创建自己的类型。我没有深入阅读链接的文章,但它看起来像是使用了反射。Emit可以快速创建新类型;但是如果您将讨论限制在C本身的范围内,您就不能做您想做的事情。
最好的解决方案就是不要使用匿名类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class Test { class DummyInterfaceImplementor : IDummyInterface { public string A { get; set; } public string B { get; set; } } public void WillThisWork() { var source = new DummySource[0]; var values = from value in source select new DummyInterfaceImplementor() { A = value.A, B = value.C +"_" + value.D }; DoSomethingWithDummyInterface(values.Cast<IDummyInterface>()); } public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values) { foreach (var value in values) { Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B); } } } |
请注意,您需要将查询结果强制转换为接口类型。也许有更好的方法,但我找不到。
具体问题的答案是否定的,但是你是否在研究模拟框架?我使用moq,但是有数百万个,它们允许您实现/存根(部分或全部)在线接口。如。
1 2 3 4 5 6 7 8 9 10 |
另一种选择是创建一个在构造函数中接受lambda的具体实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | public interface DummyInterface { string A { get; } string B { get; } } //"Generic" implementing class public class Dummy : DummyInterface { private readonly Func<string> _getA; private readonly Func<string> _getB; public Dummy(Func<string> getA, Func<string> getB) { _getA = getA; _getB = getB; } public string A => _getA(); public string B => _getB(); } public class DummySource { public string A { get; set; } public string C { get; set; } public string D { get; set; } } public class Test { public void WillThisWork() { var source = new DummySource[0]; var values = from value in source select new Dummy // Syntax changes slightly ( getA: () => value.A, getB: () => value.C +"_" + value.D ); DoSomethingWithDummyInterface(values); } public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values) { foreach (var value in values) { Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B); } } } |
如果您所要做的只是将
但是,如果您需要将许多类型转换为