33 votes

Passer des paramètres C # qui peuvent "s'adapter" à une interface, mais ne l'implémentent pas réellement

Note: je sais que c'est une très mauvaise idée dans la pratique; je suis juste curieux de savoir ce que le CLR vous permettre de le faire, avec l'objectif de créer une sorte de "modifier une classe après la création de ce' préprocesseur.

Supposons que j'ai la classe suivante, qui a été définie dans une autre assemblée, donc je ne peux pas le changer.

class Person {
    public string Greet() => "Hello!";
}

Je vais maintenant définir une interface, et une méthode, comme suit:

interface IGreetable {
    string Greet();
} 

// ...

void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());

La classe Person n'est pas explicitement de mettre en œuvre IGreetable, mais il pourrait le faire sans aucune modification de ses méthodes.

Avec qui, est-il quelque manière que ce soit, à l'aide de la Réflexion, de la DLR ou quoi que ce soit d'autre, dans lequel une instance d' Person pourrait être passé avec succès PrintGreeting sans modification du code ci-dessus?

28voto

Roy Sanchez Points 715

Essayez d'utiliser la bibliothèque Impromptu-Interface

Cadre [The Impromptu-Interface] pour vous permettre d’envelopper tout objet (statique ou dynamique) avec une interface statique même s’il n’en a pas hérité. Pour ce faire, il émet un code de liaison dynamique mis en cache dans un proxy.

Cela vous permet de faire quelque chose comme ça:

 var person = new Person();
var greeter = person.ActLike<IGreetable>();
 

7voto

John Koerner Points 17899

Vous pouvez utiliser un objet wrapper dynamic pour le câbler vous-même, mais vous perdez la sécurité de type à l'intérieur de la classe d'emballage:

 class GreetableWrapper : IGreetable
{
    private dynamic _wrapped;
    public GreetableWrapper(dynamic wrapped)
    {
        _wrapped = wrapped;
    }

    public string Greet()
    {
        return _wrapped.Greet();
    }
}

static void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
static void Main(string[] args)
{
    PrintGreeting(new GreetableWrapper(new Person()));
    Console.ReadLine();
}
 

6voto

Jon Hanna Points 40291

Cela peut être assez facile à bientôt. Les classes de Type peut être introduite dans le langage C# dans les formes où vous serez en mesure de définir les caractéristiques d'une classe et code contre cette forme , puis faire usage de votre code avec n'importe quel type qui correspond sans que l'auteur de ce code, d'avoir à déclarer quoi que ce soit, à peu près comme vous le décrivez.

La chose la plus proche en C# droit maintenant, c'est peut-être la façon dont foreach travaille avec un type qui a un GetEnumerator() retourner un objet d'un type avec un MoveNext() et Current même qu'ils n'implémentent pas IEnumerable etc. seulement alors que c'est un concept intégré le compilateur traite, ici vous pouvez définir.

Fait intéressant, il vous permettra également de définir les membres statiques.

4voto

Jonathan Wood Points 26443

Je ne crois pas que ce soit possible. Le compilateur a besoin de voir quelque chose qui implémente explicitement l'interface ou la classe afin qu'il puisse confirmer que tout est implémenté.

Si vous pouviez le faire en utilisant la redirection, vous pourriez ne pas mettre en œuvre quelque chose. Et cela va à l’encontre de l’approche de sécurité adoptée par .NET.

4voto

Mauri Points 29

Une option crée une classe wrapper sur la personne et passe ce wrapper à la méthode, le wrapper doit implémenter explicitement l'interface.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X