2008-10-20 11 views
5

Tengo 3 clases que son esencialmente las mismas pero no implemento una interfaz porque todas provienen de diferentes servicios web.C# Genéricos: ¿Puedo restringir a un conjunto de clases que no implementan una interfaz?

p. Ej.

  • Service1.Object1
  • Service2.Object1
  • Service3.Object1

Todos ellos tienen las mismas propiedades y le escribo algo de código para asignar el uno al otro mediante el cual un objeto intermediario implementa mi propia interfaz IObject1

he hecho esto utilizando genéricos

public static T[] CreateObject1<T>(IObject1[] properties) 
    where T : class, new() 
{ 
    //Check the type is allowed 
    CheckObject1Types("CreateObject1<T>(IObject1[])", typeof(T)); 
    return CreateObjectArray<T>(properties); 
} 

private static void CheckObject1Types(string method, Type type) 
{ 
    if (type == typeof(Service1.Object1) 
    || type == typeof(Service2.Object1) 
    || type == typeof(Service3.Object1) 
    || type == typeof(Service1.Object1[]) 
    || type == typeof(Service2.Object1[]) 
    || type == typeof(Service3.Object1[])) 
    { 
    return; 
    } 

    throw new ArgumentException("Incorrect type passed to ServiceObjectFactory::" + method + ". Type:" + type.ToString()); 
} 

Mi código de cliente se parece a:

//properties is an array of my intermediary objects 
Object1[] props = ServiceObjectFactory.CreateObject1<Object1>(properties); 

Lo que quiero hacer es deshacerse del método CheckObject1Types y el uso de restricciones en su lugar para que me sale un error de generación si los tipos no son válidas, porque en el momento en que puedo llamar a este método con cualquier tipo y el método CheckObject1Types arroja ArgumentException.

Así que me gustaría hacer algo como:

public static T[] CreateObject1<T>(IObject1[] properties) 
    where T : class, new(), Service1.Object1|Service2.Object1|Service3.Object1 
{ 
    return CreateObjectArray<T>(properties); 
} 

¿Alguna idea?

Editar: No quiero cambiar los archivos Reference.cs para cada servicio web porque todo lo que se necesita es un compañero de equipo para actualizar la referencia web y BAM! código roto

+0

Me acabo de dar cuenta de que puedo mejorar la eficiencia del código de tipos de cheque al cambiarlo de && a || y! = a == antes de que alguien lo señale. –

Respuesta

14

Suponiendo que las clases generadas son parciales, puede crear una interfaz y luego agregar otro archivo fuente parcial para que las clases generadas implementen la interfaz. Entonces puede restringir por interfaz de manera normal. No se requieren cambios en el código generado real :)

+0

Eso es un poco a lo que estaba tratando de llegar. –

+0

Buen punto sobre el truco de clase parcial. Acabo de ver un nuevo proyecto que creé en VS2008 (.NET 3.5) usando una referencia de servicio y creó el cliente como una clase parcial. –

+0

Interesante ... Voy a intentar esto. –

1

Restringir a una lista de clases en forma de "O" como lo que quiere hacer no es posible en C#. (De hecho, ni siquiera estoy seguro de que sea legal directamente en IL.)

Su única opción es seguir usando las funciones de estilo checktypes. Si posee el código para los diferentes servicios web, también puede implementar una interfaz "centinela" y usarla como su restricción. Sé que las interfaces centinelas no son prácticas recomendadas según las Pautas de diseño del marco, pero ocasionalmente tienen sus aplicaciones (esta es una de ellas).

Como señala Jon, es posible que pueda utilizar clases prtial para implementar una interfaz común. Si su References.cs implementa una clase:

namespace TestServices 
{ 
    internal partial class Service1SoapClient : System.ServiceModel.ClientBase<T>, K 
    { 
    } 
} 

A continuación, crear otra clase parcial en el mismo espacio de nombres (lo llaman References.CommonInterface.cs), que puede vivir en cualquier parte de su proyecto, con lo siguiente:

namespace TestServices 
{ 
    internal interface ICommon 
    { 
    } 

    internal partial class Service1SoapClient : ICommonInterface 
    { 
    } 
} 
+0

¡Muy bien, espero que hayas demostrado que estás equivocado! ¿Alguna expansión de por qué esto es? No poseo el código - sí, podría ir a través de Reference.cs y asignar manualmente cada clase a una interfaz común, pero si un compañero de equipo actualiza las referencias web - ¡BAM! No más interfaz. –

+0

Consulte la respuesta de Jon Skeet sobre la posibilidad de utilizar clases parciales para derivar todo desde una interfaz común. –

+0

Consulte este artículo sobre por qué no se implementó la capacidad de "cambiar de tipo", que probablemente tiene muchas de las mismas razones. http://blogs.msdn.com/peterhal/archive/2005/07/05/435760.aspx –

-2

Si extrae estos objetos de un servicio web, definitivamente tiene control sobre las definiciones de clase utilizadas. No solo surgen de la nada (incluso si tienes un generador de código o un estudio visual que los crean inicialmente). Todavía hay un archivo de clase para cada uno de ellos en algún lugar que debe compilarse con la aplicación, y usted debería poder agregar su interfaz común a esas definiciones de clase.

+0

Vea mi comentario sobre la respuesta de Scott Dorman. –

+0

¿No es eso para lo que es el control de fuente? –

+0

Es cierto, simplemente no me gusta hacer eso, supongo. Código olor? –

0

Escribiría una clase de convertidor que tomara cualquiera de sus tres objetos en un objeto nuevo que admita la interfaz que desea. Además, utilizaría la reflexión para no tener que escribir todas las asignaciones manualmente (a menos que sea un objeto pequeño y no se espera que cambie demasiado).

El uso de Reflection también le daría la garantía de que desea asegurarse de que los objetos implementen las propiedades que implemente su nuevo objeto Interfaced; de lo contrario, cuando una propiedad esperada no se implemente podría generar un error.

Cuestiones relacionadas