Tengo una aplicación de código abierto de terceros que exporta una interfaz COM, que estoy usando en mi aplicación C# .NET a través de Interop. Esta interfaz COM exporta muchos objetos que se muestran como System.Object hasta que los transfiero al tipo de interfaz apropiado. Quiero asignar una propiedad de todos estos objetos. Por lo tanto:función genérica con una restricción "tiene la propiedad X"?
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
Pero la asignación de la propiedad es probable que (por razones específicas de la aplicación que son inevitables) para lanzar excepciones de la que desea recuperar, por lo que realmente quiere un try/catch alrededor de cada uno. Por lo tanto:
foreach (object x in BigComInterface.Chickens)
{
try
{
(x as Chicken).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
foreach (object x in BigComInterface.Ducks)
{
try
{
(x as Duck).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
Obviamente, sería mucho más limpio para hacer esto:
foreach (object x in BigComInterface.Chickens)
{
SetAttribute<Chicken>(x as Chicken, value);
}
foreach (object x in BigComInterface.Ducks)
{
SetAttribute<Duck>(x as Duck, value);
}
void SetAttribute<T>(T x, System.Object value)
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
ver el problema? Mi valor x puede ser de cualquier tipo, por lo que el compilador no puede resolver .tributo. Chicken y Duck no están en ningún tipo de árbol de herencia y no comparten una interfaz que tenga .tributo. Si lo hicieran, podría poner una restricción para esa interfaz en T. Pero dado que la clase es de código cerrado, eso no es posible para mí.
Lo que quiero, en mi fantasía, es algo así como una restricción que requiere que el argumento tenga la propiedad .attribute independientemente de si implementa una interfaz determinada. A saber,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
no estoy seguro de qué hacer a partir de aquí aparte de cortar/pegar este pequeño bloque try/catch para cada una de pollo, pato, vaca, oveja, y así sucesivamente.
Mi pregunta es: ¿Cuál es una buena solución para este problema de querer invocar una propiedad específica en un objeto cuando la interfaz que implementa esa propiedad no puede conocerse en tiempo de compilación?
Gracias, Reed. Probé la técnica de Reflexión: hace lo que necesito pero es un poco lento. – catfood
Como no hay una interfaz común, no hay forma de hacer la invocación genérica basada en el vtable rápido: tiene que hacer una búsqueda dinámica en el nombre, y esto siempre es lento, Reflexión o no. –
@Pavel: Sí, siempre es lento, pero técnicamente, es la única forma de que funcione sin cambiar las clases existentes, hasta que C# 4 se apague. No digo que sea bueno, sino que funcionaría. –