有可能让匿名类型实现接口吗?

我有一段代码,我想工作,但不知道如何做到这一点。

我已经得到了几个答案,要么说不,要么创建一个实现接口的类,构造它的新实例。这并不是很理想,但我想知道是否有一种机制可以在接口之上创建一个精简的动态类,从而使这变得简单。

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#编程指南:

匿名类型是由一个或多个公共只读属性组成的类类型。不允许使用其他类型的类成员,如方法或事件。匿名类型不能强制转换为除对象以外的任何接口或类型。

其他回答

匿名类型可以通过动态代理实现接口。

我在GitHub上写了一个扩展方法,并在http://wblo.gs/feE上发表了一篇博文来支持这种情况。

该方法可以这样使用:

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; }
}

另一种选择是创建一个单独的、具体的实现类,在构造函数中接受lambdas。

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);
        }
    }
}

如果你所要做的只是将DummySource转换为DummyInterface,那么在构造函数中使用一个DummySource并实现接口的类会更简单。

但是,如果您需要将许多类型转换为DummyInterface,这就少了很多。

没有;匿名类型除了具有一些属性外,不能做任何事情。您需要创建自己的类型。我没有深入阅读链接的文章,但它似乎使用了反射。Emit动态创建新类型;但是如果你把讨论局限在c#内部,你就不能做你想做的事情。

不,匿名类型不能实现接口。摘自c#编程指南:

匿名类型是由一个或多个公共只读属性组成的类类型。不允许使用其他类型的类成员,如方法或事件。匿名类型不能强制转换为除对象以外的任何接口或类型。

虽然这篇文章中的答案都是正确的,但我还是忍不住要告诉您,让匿名类实现接口实际上是可能的,尽管这需要一些创造性的欺骗。

回到2008年,我正在为我当时的雇主编写一个定制的LINQ提供程序,在某个时刻,我需要能够区分“我的”匿名类和其他匿名类,这意味着让它们实现一个接口,我可以使用它来进行类型检查。我们解决这个问题的方法是使用方面(我们使用PostSharp),直接在IL中添加接口实现。所以,实际上,让匿名类实现接口是可行的,你只需要稍微改变一下规则就可以了。