2009-02-19 17 views
6

que actualmente tienen este tipo de código:C#: Fundición tipos dinámicamente

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    if (MainObject is SomeClassType1) 
    { 
     SomeClassType1 HelpObject = (SomeClassType1)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     SomeClassType2 HelpObject = (SomeClassType2)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
} 

Suponiendo que SomeClassType1 y SomeClassType2 tienen el mismo conjunto de propiedades que desea asignar (aunque pueden diferir en otras), es Es posible emitir dinámicamente MainObject al tipo apropiado y luego asignar el valor, sin duplicar el código? Esto es lo que me gustaría ver en el final:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type DynamicType = null; 

    if (MainObject is SomeClassType1) 
    { 
     DynamicType = typeof(SomeClassType1); 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     DynamicType = typeof(SomeClassType2); 
    } 

    DynamicType HelpObject = (DynamicType)MainObject; 
    HelpObject.Property1 = Arg1; 
    HelpObject.Property2 = Arg2; 
} 

Y, obviamente, C# queja de no poder encontrar DynamicType:

El tipo o espacio de nombres 'DynamicType' no se pudo encontrar (¿Echas en falta una directiva using o una referencia de ensamblado?)

¿Algo así es posible en C# 2.0? Si es más desordenado que mi código actual, entonces no veo sentido en hacer esto, pero estoy muy interesado en saberlo. ¡Gracias!

EDIT: para aclarar, entiendo perfectamente que la implementación de una interfaz es la solución más adecuada y probablemente la correcta. Dicho esto, estoy más interesado en ver cómo podría hacerlo sin implementar una interfaz. Gracias por excelentes respuestas!

Respuesta

15

Parece que ambos tipos se preocupa por aplicar los mismos dos propiedades. En ese caso, lo que se quiere hacer es definir una interfaz para aquellas propiedades:

public interface IMyInterface 
{ 
    public Foo Property1 {get; set;} 
    public Bar Property2 {get;set;} 
} 

A continuación, asegúrese de que cada una de sus clases indicar al compilador que aplican ese nuevo interfaz. Por último, utilizar un método genérico con un argumento de tipo que está obligado a que interace:

private void FillObject<T>(T MainObject, Foo Arg1, Bar Arg2) 
    where T : IMyInterface 
{ 
    MainObject.Property1 = Arg1; 
    MainObject.Property2 = Arg2; 
} 

Tenga en cuenta que incluso con el código adicional para declarar la interfaz, estos fragmentos aún así terminar más corto que sea uno de los fragmentos en los que posteaste en la pregunta, y este código es mucho más fácil de extender si aumenta el número de tipos que le interesan.

+1

+1 Agradable ... No hubiera pensado en usar medicamentos genéricos, solo habría lanzado a la interfaz. –

+0

¿Cómo es útil el Parámetro genérico T aquí? ¿Por qué no simplemente usar FillObject (IMYInterface mainobject, ...)? –

+0

Tengo curiosidad: ¿por qué usaría genéricos en este caso y no solo en el vacío privado FillObject (IMyInterface MainObject, Foo Arg1, Bar Arg2)? –

9

Esencialmente, lo que estás haciendo aquí es escribir una instrucción switch basada en el tipo de objeto. No hay una forma intrínsecamente buena de hacer esto que no sea su primer ejemplo (que en el mejor de los casos es tedioso).

Escribí un pequeño marco para encender los tipos que hace que la sintaxis sea un poco más conciso. Le permite escribir código como el siguiente.

TypeSwitch.Do(
    sender, 
    TypeSwitch.Case<Button>(
     () => textBox1.Text = "Hit a Button"), 
    TypeSwitch.Case<CheckBox>(
     x => textBox1.Text = "Checkbox is " + x.Checked), 
    TypeSwitch.Default(
     () => textBox1.Text = "Not sure what is hovered over")); 

en blog: http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

2

En lugar de tratar de fundido, tal vez usted podría tratar de definir las propiedades que utilizan la reflexión.

4
private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type t = MainObject.GetType(); 

    t.GetProperty("Property1").SetValue(MainObject, Arg1, null); 
    t.GetProperty("Property2").SetValue(MainObject, Arg2, null); 
} 
+0

Creo que los medicamentos genéricos son más apropiados aquí, pero al menos comprobaría para asegurarse de que las propiedades existen primero. –

+0

Solo quería demostrar la forma en que lo haces con reflexión. Este no es el enfoque * completo * o * recomendado * para este problema. –

+0

Creo que esto tiene un desastre escrito por todas partes ... –

7

¿Podrá hacer cambios en SomeClassType1, SomeClassType2, etc.? En caso afirmativo, le sugiero que cree una interfaz que contenga sus propiedades comunes y luego encasille a esta interfaz dentro de FillObject() para establecer las propiedades.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SO566510 
{ 
    interface IMyProperties 
    { 
     int Property1 { get; set; } 
     int Property2 { get; set; } 
    } 

    class SomeClassType1 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 

    class SomeClassType2 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj1 = new SomeClassType1(); 
      var obj2 = new SomeClassType2(); 

      FillObject(obj1, 10, 20); 
      FillObject(obj2, 30, 40); 

     } 

     private static void FillObject(IMyProperties objWithMyProperties 
            , int arg1, int arg2) 
     { 
      objWithMyProperties.Property1 = arg1; 
      objWithMyProperties.Property2 = arg2; 
     } 
    } 
} 
+0

Si bien eso es ciertamente una opción, será una exageración por lo simple que estoy tratando de lograr. Mi código es básicamente lo que publiqué anteriormente, con solo unos pocos tipos y nombres var cambiados. –

+0

Estaba a punto de sugerir lo mismo. Si tienen las mismas propiedades disponibles públicamente, una interfaz parece ser apropiada. –

+0

@MK_Dev: No es tanto trabajo lo que piensas que es, tienes que intentarlo. De hecho, podría terminar reduciendo el tamaño de tu código. –

3

Algunas ideas:

  1. tienen ambos tipos heredan del mismo tipo que tiene las propiedades comunes
  2. tienen ambos tipos implementar la misma interfaz que tiene las propiedades comunes
  3. utilizar la reflexión para establecer las propiedades en lugar de establecerlos directamente (esto es probablemente más feo de lo que vale)
  4. Use el nuevo dynamic feature, no lo he intentado, pero parece que podría abordar su problema
0

estoy dinámicamente Conversión de objetos que utilizan la reflexión en una aplicación ASP.NET MVC. Básicamente, enumero las propiedades de una clase, encuentro el valor correspondiente en el data store y dinámicamente echo el valor y lo asigno a la instancia del objeto. Ver mi publicación en el blog Dynamic Casting with .NET