47 votes

Erreur "impossible d'implémenter le membre d'interface" lorsque l'interface et le béton sont dans des projets différents

Cela compile:

 public interface IMyInterface
{
    event Action<dynamic> OnSomeEvent;
}

class MyInterface : IMyInterface
{
    public event Action<dynamic> OnSomeEvent;
}
 

Mais lorsque je sépare l'interface et la mise en œuvre de différents projets, je reçois:

L'accesseur 'TestProject2.MyInterface.OnSomeEvent.remove' ne peut pas implémenter le membre d'interface 'InterfaceNamespace.IMyInterface.remove_OnSomeEvent (System.Action)' pour le type 'TestProject2.MyInterface'. Utilisez une implémentation d'interface explicite.

Cela se produit uniquement avec un paramètre dynamique ...

30voto

Jon Skeet Points 692016

Bonne prise. Cela ressemble c'est probablement un bug du compilateur C# - je vais ping Eric Lippert pour voir ce qu'il en pense. (dynamic peut être un peu tricksy; il peut aussi être une bonne mais non de raison évidente pour cette erreur.)

EDIT: Le code ci-dessous s'affiche pas au travail après tout. J'aurais juré que je l'ai eu à travailler ce matin... je suis très confus quant à ce qu'il se passe. Comme par Simon commentaires, le code échoue avec un message disant qu'il n'est pas pris en charge par le langage.

Notez que si vous n' utilisez explicite de l'interface de mise en œuvre, il apparaît à compiler fine:

// Doesn't actually compile - see edit above
class MyInterface : IMyInterface
{
    private Action<dynamic> foo;

    event Action<dynamic> IMyInterface.OnSomeEvent
    {
        // TODO (potentially): thread safety
        add { foo += value; }
        remove { foo -= value; }
    }
}

EDIT: Le reste de cette réponse tient toujours...

Notez que vous ne pouvez pas spécifier un champ comme événement comme une manière explicite-mise en œuvre de l'événement, c'est à dire ce qui ne fonctionne pas:

event Action<dynamic> IMyInterface.OnSomeEvent;

Il donne le message d'erreur suivant:

Test.cs(15,39): erreur CS0071: Une interface explicite la mise en œuvre d'un événement doit utiliser l'événement de l'accesseur de la syntaxe

Et si vous juste essayer de faire changer le cas de l'accesseur de la syntaxe, vous obtenez la même erreur que les code d'origine.

Notez que la modification de l'événement à une propriété fonctionne très bien avec une auto-mise en œuvre de la propriété de la mise en œuvre.

9voto

Eric Lippert Points 300275

Merci d'avoir posté cette question, et merci à Jon de l'avoir envoyée à ma façon. Je l'ai mis dans la file d'attente d'un de nos testeurs spécialisé dans le "dynamique". Nous verrons si nous pouvons comprendre ce qui se passe ici. Ça sent certainement un insecte.

À l'avenir, envisagez de publier de telles choses sur connect.microsoft.com; cela permet aux testeurs d’être encore plus rapides et nous offre un meilleur mécanisme pour obtenir plus d’informations sur le problème.

2voto

Caspar Kleijne Points 11850

Cette réponse est à elborate mes pensées sur cet intéressant problème. Pas une vraie réponse, mais une contribution à l'ensemble de la discussion qui est trop petit pour un commentaire normal.

J'ai vérifié un peu les choses, cette interface:

namespace DifferentAssemblyNamespace
{
    public interface IBar
    {
        event Action<dynamic> OnSomeEvent;
    }
}

et sa mise en œuvre:

// implicit interface implementation
// generates compile error "Explicit interface implementation"
public class Foo1 : IBar
{
    private Action<dynamic> foo;
    public event Action<dynamic> OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

// implicit interface implementation
// generates compile error "Not supported by the language"
public class Foo2 : IBar
{
    private Action<dynamic> foo;

    event Action<dynamic> IBar.OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

ne fonctionnera jamais, semble qu'une règle est à l'exclusion de l'autre nécessaires à la règle.

mais.. si nous appelons de médicaments pour l'aider, et l'utilisation d'un paramètre de Type, au lieu d'utiliser dynamic directement avec:

namespace DifferentAssemblyNamespace
{
    public interface IGenericBar<T>
    {
        event Action<T> OnSomeEvent;
    }
}

et sa mise en œuvre.

// implicit interface implementation
public class Foo3<T> : IGenericBar<T>
{
    private Action<T> foo;

    event Action<T> IGenericBar<T>.OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

pour une raison quelconque, nous pouvons construire (comme il se doit) et exécutez:

/** does build **/
IGenericBar<dynamic> f = new Foo3<dynamic>();
f.OnSomeEvent += new Action<dynamic>(f_OnSomeEvent);

semble que le Paramètre Type fait quelque chose de plus que le compilateur est heureux avec.

Je ne suis pas sûr de ce qui se passe, donc je voudrais savoir en tant que bien.

l'hypothèse, hautement hypothétique (peut-être de la merde)

mais actuellement, j'ai mis mes deux cents sur la comparaison des types il doit y avoir fait via l'ajout/suppression de accesseurs en la liste, qui détient le cible/méthodes de l'événement.

Je parie que le compilateur tombe sur la problème qu'il ne peut pas garantir que dynamique est à l'extérieur de l'assemblée, ne peut donc pas déterminer si un élément est déjà dans la liste ou pas, ce qui est nécessaire pour les ajouter ou les supprimer.(D'où explicite de l'implémentation de l'interface)

Nous savons tous que c'est juste une partie d'un attribué objet, mais il semble encore qu'il a besoin d'une étape supplémentaire où certains fort-type est garanti, et c'est ce T n'a, au moment de la compilation.

/ hypothèse, hautement hypothétique (peut-être de la merde)

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