Une Classe C # anonyme peut-elle implémenter une interface?

Est-il possible d'avoir un type anonyme implémenter une interface. J'ai un morceau de code que je voudrais travailler, mais vous ne savez pas comment faire cela.

J'ai eu quelques réponses qui disent non, ou créent une classe qui implémente l'interface construire de nouvelles instances de cela. Ce n'est pas vraiment idéal, mais je me demande s'il existe un mécanisme pour créer une classe dynamique mince au-dessus d'une interface qui rendrait cela simple.

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

J'ai trouvé un article wrapping d'interface dynamique {[7] } qui décrit une approche. Est-ce la meilleure façon de le faire?

386
demandé sur Patrick McDonald 2008-10-10 16:20:32

7 réponses

Non, les types anonymes ne peuvent pas implémenter une interface. De la C # Guide de programmation :

Les types anonymes sont des types de classes constitués d'une ou de plusieurs propriétés publiques en lecture seule. Aucun autre type de membres de classe, tels que des méthodes ou des événements, n'est autorisé. Un type anonyme ne peut pas être converti sur une interface ou un type à l'exception de l'objet.

306
répondu SpaceghostAli 2014-07-17 12:15:38

Bien que cela puisse être une question de deux ans, et bien que les réponses dans le fil soient toutes assez vraies, Je ne peux pas résister à l'envie de vous dire qu'il est en fait possible d'avoir une classe anonyme implémenter une interface, même s'il faut un peu de tricherie créative pour y arriver.

En 2008, j'écrivais un fournisseur LINQ personnalisé pour mon employeur d'alors, et à un moment donné, j'avais besoin de pouvoir dire " mes " classes anonymes à partir d'autres classes anonymes, ce qui signifiait avoir ils implémentent une interface que je pourrais utiliser pour taper les vérifier. La façon dont nous l'avons résolu en utilisant les aspects (nous avons utilisé PostSharp), pour ajouter l'implémentation de l'interface directement dans l'IL. Donc, en fait, laisser des classes anonymes implémenter des interfaces est faisable , Il suffit de plier légèrement les règles pour y arriver.

81
répondu Mia Clarke 2011-05-30 14:41:57

Lancer des types anonymes sur des interfaces a été quelque chose que je voulais depuis un moment, mais malheureusement, l'implémentation actuelle vous oblige à avoir une implémentation de cette interface.

La meilleure solution est d'avoir un type de proxy dynamique qui crée l'implémentation pour vous. En utilisant l'excellent projet LinFu Vous pouvez remplacer

select new
{
  A = value.A,
  B = value.C + "_" + value.D
};

Avec

 select new DynamicObject(new
 {
   A = value.A,
   B = value.C + "_" + value.D
 }).CreateDuck<DummyInterface>();
39
répondu Arne Claassen 2015-05-23 12:46:16

Non; un type anonyme ne peut rien faire sauf avoir quelques propriétés. Vous aurez besoin pour créer votre propre type. Je n'ai pas lu l'article lié en profondeur, mais il semble qu'il utilise la réflexion.Emit pour créer de nouveaux types à la volée; mais si vous limitez la discussion aux choses dans C # lui-même vous ne pouvez pas faire ce que vous voulez.

12
répondu Marc Gravell 2008-10-10 12:25:22

Les types anonymes peuvent implémenter des interfaces via un proxy dynamique.

J'ai écrit une méthode d'extension sur GitHub et un article de blog http://wblo.gs/feE {[5] } pour soutenir ce scénario.

La méthode peut être utilisée comme ceci:

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; }
}
12
répondu Jason Bowers 2014-11-09 05:08:22

La meilleure solution est de ne pas utiliser de classes anonymes.

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

Notez que vous devez convertir le résultat de la requête au type de l'interface. Il pourrait y avoir une meilleure façon de le faire, mais je ne pouvais pas le trouver.

11
répondu ICR 2015-05-26 09:15:35

La réponse à la question spécifiquement posée est non. Mais avez-vous regardé des cadres moqueurs? J'utilise MOQ mais il y en a des millions et ils vous permettent d'implémenter/stub (partiellement ou entièrement) des interfaces en ligne. Par exemple.

public void ThisWillWork()
{
    var source = new DummySource[0];
    var mock = new Mock<DummyInterface>();

    mock.SetupProperty(m => m.A, source.Select(s => s.A));
    mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));

    DoSomethingWithDummyInterface(mock.Object);
}
7
répondu Nine Tails 2014-07-31 16:37:35