2012-10-09 5 views
6

Tengo una interfaz ISnack que, cuando la implementa una clase, debe tener un constructor sin parámetros predeterminado. Básicamente esto:Existe una forma de aplicar el constructor sin parámetros sin la restricción genérica

public interface ISnack<T> where T : new() 
{ 

} 

utilizo <T> where T : new() sólo para hacer cumplir el constructor sin parámetros.

me permitiría implementar la interfaz de esta manera:

public class Cutlet : ISnack<Cutlet> 
{ 

} 

Esto funciona y simplemente asegura Cutlet clase tiene un constructor sin parámetros.

Ahora tienen una clase base abstracta Kitchen:

public abstract class Kitchen<T> where T : ISnack 
{ 

} 

El requisito es que debe tener restricción Kitchen donde T debería haber una ISnack. Pero esto no funcionará porque no existe ISnack, pero solo ISnack<T>.

Si tratara este

public abstract class Kitchen<T> where T : ISnack<T> 
{ 

} 

no compile ('T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'ISnack<T>') y además no tendría sentido en mi contexto.

Si pudiera forzar ISnack s tener un constructor sin parámetros sin restringir por un parámetro T tipo, entonces T en Kitchen<T> podría fácilmente ser una ISnack. ¿Cómo hacerlo?

Respuesta

10

No puede hacerlo a menos que agregue la restricción; restricciones genéricas son acumulativos, por lo que para hacer el compilador feliz que tendría que tener:

public abstract class Kitchen<T> where T : ISnack<T>, new() 

Si eso está muy bien, luego hacer que. Si no está bien, tendrá que eliminar el : new del original y prescindir de él. Esto no es tan malo como parece, pero significa que debes pasar la validación a la ejecución en lugar de a la compilación. Pero: Activator.CreateInstance<T>() sigue haciendo lo que necesita, de todos modos, incluso sin la restricción new(). Para que pueda reemplazar:

T newObj = new T(); // validated by the compiler 

con:

T newObj = Activator.CreateInstance<T>(); // not validated until executed 

Un truco muy útil cuando las restricciones de eliminación pueden ser: agrega una prueba de unidad/integración que encuentra los tipos de candidatos a través de la reflexión, y validar la restricción que falta como parte de su suite de prueba.

+0

Marc, ¡De acuerdo! has resumido todo lo que he intentado ... Hmmm runtime es la opción que tengo Supongo – nawfal

+1

@nawfal Si está bien, puedes agregar un segundo argumento genérico a la cocina y esto debería funcionar: 'abstact class Kitchen donde T: ISnack donde S: new() ' –

+0

@FelixK. ¿puedes hacer que sea otra respuesta? – nawfal

1

sólo tiene que añadir la restricción de T de nuevo

public abstract class Kitchen<T> where T : ISnack<T>, new() {  } 
3

Se puede utilizar un segundo parámetro genérico:

abstact class Kitchen<T, S> 
    where T : ISnack<S> 
    where S : new() 
.... 

Esto va a resolver su problema.

Agregar un segundo parámetro a una clase también puede causar algunos problemas que he enfrentado desde .NET 2.0 está disponible. Algunas situaciones complejas pueden requerir agregar parámetros más genéricos a las clases de lo que desea. Normalmente rompo la cadena genérica agregando moldes más directos (como (SpecificType)base.MyTypeTProperty). Comentario: Intento buscar una muestra más adelante

+0

esto también funciona, pero supongo que es menos elegante que el sugerido por Marc – nawfal

+0

@nawfal Por supuesto, y puede causar problemas en situaciones más complejas. Tal vez voy a publicar un ejemplo más tarde. –

Cuestiones relacionadas