Pregunta

¿Es posible construir un objeto con su constructor interna dentro de un método genérico?

public abstract class FooBase { }

public class Foo : FooBase {
   internal Foo() { }
}

public static class FooFactory {
    public static TFooResult CreateFoo<TFooResult>()
    where TFooResult : FooBase, new() {
        return new TFooResult();
    }
}

reside FooFactory en la misma Asamblea que Foo. Clases llaman el método de fábrica de esta manera:

var foo = FooFactory.CreateFoo<Foo>();

Se consigue el error de tiempo de compilación:

  

'Foo' debe ser un tipo no abstracto con un constructor sin parámetros pública con el fin de utilizarlo como parámetro 'TFooType' en el tipo genérico o método 'FooFactory.CreateFoo ()'

¿Hay alguna forma de evitar esto?

También intentó:

Activator.CreateInstance<TFooResult>(); 

Esto plantea el mismo error en tiempo de ejecución.

¿Fue útil?

Solución

Se puede eliminar la restricción new() y el retorno:

//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true); 

A pesar de que el cliente pudiera hacer eso también. Esto, sin embargo, es propensa a errores de tiempo de ejecución.

Este es un problema difícil de resolver de una manera segura ya que el lenguaje no permite una declaraton constructor abstracto.

Otros consejos

  

El argumento tipo debe tener una    público sin parámetros constructor. Cuando se usa junto con otro   limitaciones, la nueva () debe restricción   especificarse pasado.

http://msdn.microsoft.com/en-us/library /d5x73970.aspx

edit: lo que no, si se utiliza nueva restricción (), no se puede pasar esa clase, si no utiliza nueva restricción () puede intentar utilizar la reflexión para crear nueva instancia

public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
        {
            return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
            //return new TFooResult();
        }

Hay pocos soluciones temporales como abajo, pero no creo que quiere ir de esa manera!

  • instrucción switch poner dentro de la fábrica que va a crear la instancia basada en el tipo de parámetro de tipo.

  • Cada aplicación concreta de FooBase se registrará en FooFactory pasando el método de fábrica para crearlo uno mismo. Así FooFactory utilizará el diccionario interno

  • Extendiéndose sobre la línea similar, excepto mapeo entre parámetro de tipo y aplicación concreta sería código externo (archivo XML, configuración, etc.). contenedores COI / DI también pueden ser útiles aquí.

public class GenericFactory
{
    public static T Create<T>(object[] args)
    {
        var types = new Type[args.Length];
        for (var i = 0; i < args.Length; i++)
            types[i] = args[i].GetType();

        return (T)typeof(T).GetConstructor(types).Invoke(args);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top