2009-12-07 13 views
12

decir que tengo una clase que implementa BaseClass IBaseClassC# exponer a COM - herencia de interfaces

entonces tengo una iclass interfaz que hereda IBaseClass.

Luego tengo una clase llamada clase que implementa IClass.

Por ejemplo:

[ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")] 
public interface IBaseClass 
{ 
    [PreserveSig] 
    string GetA() 
} 

[ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")] 
public interface IClass : IBaseClass 
{ 
    [PreserveSig] 
    string GetB() 
} 

[ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")] 
public class BaseClass : IBaseClass 
{ 
    public string GetA() { return "A"; } 
} 

[ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")] 
public class Class : BaseClass, IClass 
{ 
    public string GetB() { return "B"; } 
} 

Al exponer a COM, si hago una instancia de "clase" que no permite que llame a Geta().

Al mirar mi IDL en el archivo .tlb, mi interfaz iclass parece:

[ 
    odl, 
    uuid(XXXXXXXXXXXXXXXXXXXXX), 
    version(1.0), 
    dual, 
    oleautomation, 

] 
interface IClass : IDispatch { 
    [id(0x60020000)] 
    BSTR GetB(); 
} 

No siquiera se parece iclass deriva de IBaseClass!

Si saco donde IClass se deriva de IBaseClass y simplemente agrego los métodos a la interfaz, funciona.

¿Cómo puedo hacer que C# habilite esta herencia en COM? Prefiero no volver a implementar interfaces cuando puedo heredarlas.

CRAP: comprobar este enlace .Net COM Limitation

Si alguien tiene una respuesta a por qué esto es, o una solución mejor que copiar y pegar a mi interfaz "derivados", que me haga saber. Si no, marcaré una respuesta en un par de días.

+0

Necesita consultar las otras interfaces para acceder a métodos en ellas. Dependiendo del idioma del que use el objeto, podría ser un inconveniente. Para solucionarlo, necesita crear una interfaz "plana" para cada clase o dejar que el compilador lo haga por usted con "ClassInterface" (que tiene otros problemas) – adrianm

+1

Si ve mi enlace, el contestador menciona que .Net lo hace no aplique interfaces base a las interfaces COM cuando se exporte. En otras palabras, debe copiar y pegar la definición de la interfaz base para simular una interfaz base. – jonathanpeppers

+1

Creo que debería publicar su propio enlace .Net COM Limitation como una respuesta: es la solución correcta, y se recomienda publicar su propia respuesta si lo descubrió usted mismo. – bacar

Respuesta

11

Esto no es un problema de .NET, es una consecuencia de la forma en que funciona COM. No es compatible con la herencia. Usted arreglaría esto en el lado del cliente, necesita llamar a QueryInterface() con el IID para IBaseClass para obtener un puntero de interfaz a la interfaz IBaseClass para que pueda llamar a GetA(). .NET interop proporciona automáticamente una implementación de QI que hace que esto funcione. Sin embargo, no es muy fácil de usar en este caso, diseñe su código de lado C# para que sea más fácil para el cliente usar su clase en lugar de al revés. Normalmente necesitaría un método de anulación de una línea que delegue en la implementación de la clase C# base.

Tenga en cuenta que existe un problema con las firmas de sus métodos y el uso del atributo [PreserveSig]. No se pueden llamar a través de IDispatch ni se pueden ordenar automáticamente. Eso requiere un método con HRESULT como el tipo de valor devuelto. Es automático cuando quitas el atributo.

+0

Originalmente configuré [PreserveSig] para facilitar el uso con mis pruebas en VBScript (que quiere jugar con los parámetros), pero funciona igual sin (y tiene la definición IDL adecuada). Voy a replicar métodos en la clase base para evitar que el cliente tenga que llamar a QueryInterface. – jonathanpeppers

+1

En mi humilde opinión esto ** es ** un problema de .NET, COM ** totalmente ** admite * interfaz * (no clase) herencia, y regasm podría haber generado un TLB que tenía IClass derivado de ** ComVisible ** IBaseClass. Observo que cuando esto sucede, la implementación IDispatch de Class tampoco tiene conocimiento de los métodos IBaseClass, muy decepcionante. Su consejo (QI) es bueno en el caso donde un coclass implementa múltiples interfaces; de acuerdo con el MVP en el enlace de Jonathan, esa técnica no funcionará con una herencia _hierarchy_ porque simplemente no es compatible. – bacar

+0

@bacar: la agregación es posiblemente el mejor término. De todos modos, se necesita una clase concreta para implementar realmente las interfaces. Y para hacer que las interfaces COM heredadas funcionen, el compilador necesita generar múltiples tablas v, una para cada interfaz. Eso solo es compatible con entornos de tiempo de ejecución que admiten herencia múltiple. .NET no es uno de ellos, una limitación bastante fundamental. Sí, podrías llamar a eso un problema .NET, no te llevará a ninguna parte. –

6

Esto parece ser muy similar a esta pregunta: Interface inheritance in ComVisible classes in C#

Como se señala en su edición, se trata de una limitación en el .NET a COM salto, que la interfaz COM no incluye las interfaces heredadas.

En algunos idiomas podría haber resuelto esto inculding un bloque de código en todas las interfaces relevantes, pero hasta donde puedo ver esto no es posible en C#.

+0

Resulta que esto va a ser un trabajo extra molesto para que nuestro ensamblaje sea visible. – jonathanpeppers

0

Aquí hay un enfoque diferente que minimiza el trabajo y deja la interfaz limpia.
acaba de proporcionar una propiedad adicional que devuelve el BaseInterface:

public IBaseClass BaseProperties { 
    get { return this; } 
} 

Por supuesto que hay que añadir thise parte en su interfaz IBaseClass:

public ISingleShot BaseProperties { get; } 



Este es el código correspondiente VB.Net :

ReadOnly Property BaseProperties As ISingleShot 
Public ReadOnly Property BaseProperties As IBaseClass Implements IClass.BaseProperties 
    Get 
    Return Me 
    End Get 
End Property 
0

use [InterfaceType (ComInterfaceType.Interf aceIsIUnknown)] como un atributo para la interfaz que extiende a los demás. es una solución.

Cuestiones relacionadas