2009-02-18 15 views
5

Tengo una interfaz y dos clases que implementan la interfaz. Las clases tienen tipos genéricos. Me gustaría clonar de una instancia de una clase a la otra.C# Generic Copy Constructor

interface IFoo 
{ 
    // stuff 
} 

class Foo<T> : IFoo 
{ 
    // foo stuff 
    // ifoo implementation 
} 

class Bar<T> : IFoo 
{ 
    // bar stuff 
    // ifoo implementation 
} 

Tengo un Foo y me gustaría un bar. Bar tiene un constructor de copia que toma un parámetro de IFoo. creé un método de extensión para implementar el clon:

public static Bar<T> Clone<T>(this IFoo foo) 
{ 
    return new Bar<T>(foo); 
} 

Al llamar al método requiere el tipo:

someFoo.Clone<T> ... 

¿Hay una manera de omitir declarar el tipo al llamar al método modificando el método de extensión , o de cualquier otra manera, para permitir que la instancia sea pasada sin preocuparse por su tipo subyacente?

Actualización Así es como se está utilizando esto para ilustrar mejor la situación.

En un método iterar una colección y devolver una enumeración de IFoo. En el método, miro un atributo de la colección fuente y determino el tipo de Foo.

IFoo foo = null; 

string type = element.Attribute("Type").Value; 
switch (type) 
{ 
    case "int": 
     foo = new Foo<int>(); 
     break; 

    case "string": 
     foo = new Foo<string>(); 
     break; 

    // etc 
} 
// other stuff 

yield return foo; 

El método de llamada tiene una lista. Más tarde, selecciono elementos individuales de esta lista para su uso, en ese punto me gustaría un Bar en lugar de un Foo. Al seleccionar de la lista, las instancias son del tipo IFoo, ya que solo ven los métodos de extensión para "this IFoo foo". No quiero lanzar el IFoo a un Foo, eso requeriría volver a declarar el tipo de T. Me gustaría que Foo le dijera a Bar qué es. es posible?

+0

Quizás me esté faltando algo, pero si Tu función de extensión toma un IFoo, ¿cómo se supone que debe "Clonarlo" en una barra si es de tipo Foo? –

+0

Lo único que me importa son los valores en las propiedades IFoo que se copian de un Foo a una barra. – blu

Respuesta

0

Si funciona para su escenario, podría tener un IFoo<T>. Además, si no le molesta tener métodos de extensión específicos, puede recibir un Foo<T>. Realmente necesita pasar algo que haga referencia a la T para que el compilador pueda inferir el tipo apropiado.

0

Cuando se necesita un control completo sobre su clon copia profunda, este patrón es muy buena:

public class FooBase 
{ 
    private int x; 

    public FooBase() { /* standard contructor */ } 

    protected FooBase(FooBase clone) 
    { 
     this.x = clone.x; 
    } 

    public FooBase Clone() { return new FooBase(this); } 
} 

public class Foo : FooBase 
{ 
    private int y; 

    public Foo() { /* standard contructor */ } 

    protected Foo(Foo clone) : base(clone) 
    { 
     this.y = clone.y; 
    } 

    public Foo Clone() { return new Foo(this); } 
} 

Definir contructor protegida para la clonación - clases derivadas de esta forma se puede clonar los valores en la clase base. Este patrón debe estar escrito a mano (o generado con la ayuda de una buena plantilla T4) pero es muy bueno para la clonación profunda.

Actualización: Creo que he entendido mal la pregunta y ya tengo la clonación implementada. Freddy tiene razón: el compilador debe saber qué tipo debe inferir y no puede hacerlo desde el tipo IFoo. Puede hacerlo en (este Foo < T> foo) embargo.

0

Try definir el método como tal

public static Bar<T> Clone<T>(this Foo<T> foo) 
{ 
    return new Bar<T>(foo); 
} 

De esta manera, el parámetro tendría un tipo genérico y el compilador tendría una fuente para inferir el tipo de.

2

así que tienes todo bien, pero que quieren ser capaces de utilizar la sintaxis

someFoo.Clone() 

en lugar de

someFoo.Clone<int>() 

desea que el int estar implícita en lugar de tener que ponerlo Ther explícitamente ?

La razón por la que no puede hacer eso en su ejemplo de código es que IFoo no hace referencia al tipo genérico T que necesita para crear Bar<T>.

Yo sugeriría que usted realmente necesita otra interfaz: IFoo<T>

Si tuviera eso, y su método de extensión se ve así:

public static Bar<T> Clone<T>(this IFoo<T> foo) 
{ 
    return new Bar<T>(foo); 
} 

Entonces usted no tendrá ningún problema usando

IFoo<int> someFoo = new Foo<int>(); 
Bar<int> someBar = someFoo.Clone(); 

Espero que ayude