2009-10-20 12 views
19

Tengo una clase (TabControlH60) que hereda de una clase base (UserControl) e implementa una interfaz (IFrameworkClient). Instancia el objeto utilizando la clase .NET Activator. Con la instancia devuelta, puedo convertir a la clase base UserControl, pero no a la interfaz. La excepción que obtengo está debajo del código snipet. ¿Cómo echo a la interfaz?.NET: no se puede lanzar el objeto a la interfaz que implementa

object obj = Activator.CreateInstance(objType); 
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient 

m_Client = (UserControl)obj;     // base class cast works 
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails 

// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window. 
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 
    'FPG.AFF.Interfaces.IFrameworkClient'."} 

Respuesta

0

utilizar el operador :)

... 
m_Client = obj as IFrameworkClient; 
if (m_Client != null) //Remember to check for null in case the cast fails 
    ... 
... 
+0

Después de volver a leer su pregunta, no creo que esto sea lo que quería. Perdón :) – cwap

+1

El operador "como" es exactamente lo que * no * desea utilizar al depurar errores de conversión (silenciosamente se traga excepciones, dejándolo no es una manera fácil de depurar por qué falló el reparto) – ckarras

0

El reparto no está funcionando porque estás tratando de echar del tipo object a la interfaz. Si reemplaza la línea de reparto de interfaz con:

IFrameworkClient fc = (IFrameworkClient)m_Client;

Se trabajará.

De forma alternativa, estoy medianamente seguro de que podría hacer el molde del objeto a la interfaz con el operador as.

Consulte este artículo para obtener más información: http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

una pieza más del rompecabezas. Interfaces no se derivan de object: http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

+0

'm_Client' y' obj 'son casi con seguridad el mismo objeto (a menos que se defina una conversión). No espero que esto importe ... –

+0

No es así. Mi prueba funciona – Will

10

La causa más probable es que IFrameworkClient es desde un conjunto diferente en los dos casos, y es por lo tanto un tipo .NET diferente. Incluso si es el mismo código, puede ser de un tipo diferente.

Compruebe el AssemblyQualifiedName. Tenga en cuenta también que si va a cargar esta asamblea con la reflexión se puede obtener un tipo diferente incluso con el mismo AssemblyQualifiedName, gracias a la carga en el contexto.

+1

Ese fue mi primer pensamiento también. –

+0

Esa es una posibilidad, definitivamente. Referencia errónea. Pero algo así normalmente funciona cuando se depura y no funciona cuando se implementa (ensamblaje diferente en el momento del despliegue). Siempre que esto me ha pasado es porque Activator.CreateInstance no carga proactivamente todos los ensamblados asociados con un tipo que crea una instancia. – Will

+0

En mi caso, el mismo ensamblado se implementó en 2 directorios diferentes. El tipo se cargó dinámicamente en un lugar y se transfirió a la interfaz desde el otro ensamblaje. –

0

Si la clase FPG.H60.AFF.TabControlH60 realmente hace aplicar IFrameworkClient no debería haber ninguna razón de que esto sería un fracaso. La única cosa que puedo pensar en que la causa de esta excepción es si el ensamblado que contiene IFrameworkClient tiene un nombre y el objeto de control de ficha ocurre hacer referencia a una versión diferente del ensamblado que contiene o que está utilizando una interfaz diferente con el nombre IFrameworkClient.

3

Algo me dice que el código de ejemplo está dejando salir un poco de materia ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     var type = typeof(MyClass); 
     object obj = Activator.CreateInstance(type); 
     Type[] interfaces = obj.GetType().GetInterfaces(); 

     var m_Client = (UserControl)obj;   
     IFrameworkClient fc = (IFrameworkClient)obj; 
    } 
} 

public interface IFrameworkClient { } 

public class UserControl { } 

public class MyClass : UserControl, IFrameworkClient { } 

Esto compila y se ejecuta.

Apuesto a que el archivo DLL que contiene la definición de IFrameworkClient aún no se ha cargado antes de intentar lanzar. Esto puede suceder cuando estás usando Activator.CreateInstance.

Intente insertar var forceLoad = typeof(IFrameworkClient); antes del molde.

3

Definir IFrameworkClient interfaz en espacio de nombres independiente (se debe tener espacio de nombres) del proyecto independiente (biblioteca de clases) .Luego añadir refrence de la biblioteca de clases de control del proyecto y el proyecto principal

+0

Exactamente lo que hice y funciona. – broadband

28

I sombrero de los mismos problemas con una biblioteca mía que proporciona "complemento" -funcionalidad ... Lo tengo finalmente funcionando ...

Aquí estaba mi problema: tenía un ensamblaje principal usando complementos, un ensamblaje con el complemento (Plugin.dll) Y (importante) otro ensamblado que proporcionaba la funcionalidad de complemento (Library.dll).

Plugin.dll hacía referencia al ensamblaje principal (para poder ampliarlo) y el Library.dll con el plugin-func. - Los binarios han llegado a un directorio "./Plugins" relativo al ensamblaje principal.

El ensamblaje principal también hace referencia al plugin-func. ensamblado para utilizar el "PluginManager" se escribió. Este "PluginManager" obtiene una ruta y carga todos los archivos * .dll mediante reflexión para analizar si hay una interfaz "IPlugin" (que también proviene de Library.dll).

Cada vez que llamé al PluginManager para cargar los complementos, no pude convertirlos a "IPlugin" aunque lo implementaron.

Casi me enojo, pero luego descubrí todo el problema. Al compilar el complemento, no solo se escribió "Plugin.dll", sino que también se escribió "Library.dll" en el directorio "./Plugins". Al cargar accidentalmente el "Library.dll" cada vez con mi PluginManager ahora tenía dos tipos de "IPlugin": uno en el "Library.dll" real que se usa desde el ensamblaje principal y otro que se cargó a través de mi PluginManager, y ¡esos eran incompatibles!

Atención: si simplemente no carga "./Plugins/Library.dll", no obstante se encuentra con el problema, porque si carga "Plugin.dll" que hace referencia a "Library.dll", simplemente utiliza el que está en el mismo directorio ... TILT ... !! Mi PluginManager ahora solo elimina "Library.dll" donde lo encuentra.

La clave es: ¡asegúrese de no acceder a dos conjuntos en diferentes contextos!

+2

Usted, señor, acaba de hacer mi problema, que me ha estado molestando durante 4 horas por ahora, simplemente váyase. ¡Muchas gracias! – beastofman

+0

¡Esta respuesta necesita más votos ascendentes! estuvo atascado durante horas ... – MattJ

+0

Muy útil respuesta, me ha ahorrado mucho tiempo tener el problema similar. ¡Gracias! –

1

Cuando el Interface es en un montaje distinto y consigo mi clase dinámicamente en run-time en un montaje diferente, interface casting sólo podrá rechazarse como su muestra (C# conoce nuestra interfaz como un tipo diferente de la que uno la clase heredado de eso).

Esta es mi técnica sencilla y útil en estos casos:

cuando estoy seguro de que mi Class ha heredado de la mencionada Interface, así que escribir una línea de magia de (eq IFrameworkClient.) código de la siguiente manera:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj; 

Mediante esta técnica se puede:

  • Escriba sus códigos después de esta línea de código para fc en design time base sobre la información y Interface members vs sistema de inteligencias editor.
  • Prevenir cualquier error de interfaz de fundición en run-time

Notas:

  • Usted necesita C# v4 utilizar dynamic tipo
  • Por lo general, no me gusta usar dynamic tipos en mis códigos, pero nos puede ayudar en algunos casos como este
0

En mi caso, tuve que agregar un evento de compilación para copiar la DLL necesaria, ya que estaba creando instancias y asignando tipos de interfaz en tiempo de ejecución. De lo contrario, la DLL cargada podría no ser la DLL más actualizada y, por lo tanto, es posible que no se transfiera a la interfaz. El motivo por el que usé eventos de compilación en este caso (en lugar de agregar el archivo DLL como referencia) es que la arquitectura es tal que la aplicación principal solo debe hacer referencia a los tipos de interfaz, y todo lo demás debe cargarse dinámicamente.

TLDR; En el caso de tipos de carga dinámicamente desde otra DLL, asegúrese de copiar la versión más reciente de esa DLL al directorio bin utilizando eventos de compilación, de lo contrario, puede que la conversión no funcione cuando parezca que debería.

Cuestiones relacionadas