2011-05-08 643 views
46

Esto compila:de error "no se puede aplicar miembro de interfaz" cuando la interfaz y el hormigón están en diferentes proyectos

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

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

Pero cuando me separo de la interfaz y la implementación de diferentes proyectos, me sale:

accessor 'TestProject2.MyInterface.OnSomeEvent.remove' no puede implementar miembro de interfaz 'InterfaceNamespace.IMyInterface.remove_OnSomeEvent (System.Action)' para el tipo 'TestProject2.MyInterface'. Utilice una interfaz explícita implementación.

Esto se produce sólo con un parámetro dinámico ...

Respuesta

30

Buena captura. Esto parece que es posiblemente un error en el compilador de C# - Voy a hacer ping Eric Lippert para ver lo que piensa. (dynamic puede ser un poco tramposo, bien puede haber una razón perfectamente buena, pero no obvia para este error.)

EDIT: El código siguiente aparece no a trabajar después de todo. Podría haber jurado que lo hice funcionar esta mañana ... Estoy muy confundido sobre lo que está pasando. Según los comentarios de Simon, el código falla con un mensaje que dice que no es compatible con el idioma.

Tenga en cuenta que si haces uso implementación de interfaz explícita, parece compilar bien:

// 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: El resto de esta respuesta sigue en pie ...

Nota que no puede especificar un evento parecido a un campo como un evento explícitamente implementado, es decir, esto no funciona:

event Action<dynamic> IMyInterface.OnSomeEvent; 

Se da el siguiente mensaje de error:

Test.cs (15,39): CS0071 de error: Una implementación de interfaz explícita de un evento debe utilizar la sintaxis de acceso evento

Y si simplemente tratar de cambiar a la sintaxis de eventos de acceso, se obtiene el mismo error que el código original .

Tenga en cuenta que cambiar el evento a una propiedad funciona bien con una implementación de propiedad implementada automáticamente.

+1

Me pregunto cómo el compilador sabría cómo proteger anulando y luego reconocer qué hacer con dinámica al compilar los proyectos separados unos de otros. –

+0

¿Hay algo que configurar para que la implementación explícita de la interfaz funcione? Obtengo un 'error CS0682: 'ConsoleApplication1.MyInterface.ClassLibrary1.IMyInterface.OnSomeEvent' no puede implementar 'ClassLibrary1.IMyInterface.OnSomeEvent 'porque no es compatible con el error de idioma' que intenta compilar. –

+0

@Simon: ¿Qué versión del compilador de C# estás usando? Dynamic se introdujo en C# 4. –

9

Gracias por publicar esta pregunta, y gracias a Jon para enviar a mi manera. Puse esto en la cola de investigación de uno de nuestros evaluadores que se especializa en "dinámica". Veremos si podemos descubrir qué está pasando aquí. Ciertamente huele a error.

En el futuro, considere publicar cosas como esta en connect.microsoft.com; eso lo hace aún más rápido para los evaluadores, y nos brinda un mejor mecanismo para obtener más información sobre el problema.

+0

la parte divertida de todo este problema, que si pasa 'dynamic' a través de un T genérico compila fine.so public' interface IMyInterface {evento Acción OnSomeEvent;} 'y su correcta implementación que entrega es una 'ns.IMyInterface = nueva clase MyInterface ()' compila, incluso si la interfaz está en un ensamblaje diferente. ¿Envolver el 'dinámico' en una T es diferente/más estricto que usarlo directamente? –

+0

ver mi respuesta, lo elaboré. –

2

Esta respuesta es para elborar mis pensamientos sobre este interesante problema. No es una respuesta real, sino una contribución a toda la discusión que es demasiado pequeña para un comentario normal.

yo nos registramos un par de cosas, esta interfaz:

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

y su implementación:

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

nunca funcionará, parece que una regla es exclusión de la otra regla necesaria.

pero .. si llamamos a los genéricos en busca de ayuda, y el uso de un parámetro Tipodynamic en lugar de utilizar directamente como:

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

y su aplicación.

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

por alguna razón podemos construir (como debe ser) y ejecute:

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

parece que el parámetro de tipo hace algo extra que el compilador es feliz.

No estoy seguro de lo que está pasando, por lo que me gustaría saberlo también.

supuesto, altamente hipotética (quizás basura)

pero actualmente pongo mi granito de arena en la comparación de los tipos no debe ser realizar a través de Agregar/Quitar descriptores de acceso en la lista enlazada que contiene el objetivo/métodos del evento.

apuesto que el compilador cae sobre el problema que no puede garantizar lo dinámica es en el montaje externo, por lo tanto no puede determinar si un elemento ya está en la lista o no, lo que es necesario añadir o eliminarlos . (implementación de la interfaz Por lo tanto explícita)

todos sabemos que es sólo algunas de un objeto atribuido pero todavía parece que necesita un paso adicional donde se garantiza cierta de tipo fuerte, y eso es lo T hace , en tiempo de compilación.

/supuesto, altamente hipotética (quizás basura)

Cuestiones relacionadas