2009-04-01 18 views
65

En las plantillas de C++, se puede especificar que un cierto parámetro de tipo es un valor predeterminado. Es decir. a menos que se especifique explícitamente, usará el tipo T.¿Existe un enfoque razonable para los parámetros de tipo "predeterminado" en C# Generics?

¿Se puede hacer esto o aproximar en C#?

Busco algo como:

public class MyTemplate<T1, T2=string> {} 

Para que una instancia del tipo que no se especifica explícitamente T2:

MyTemplate<int> t = new MyTemplate<int>(); 

sería esencialmente:

MyTemplate<int, string> t = new MyTemplate<int, string>(); 

En última instancia estoy viendo un caso en el que hay una plantilla que es bastante amplia sed, pero estoy considerando expandirme con un parámetro de tipo adicional. Podría crear una subclase, supongo, pero tenía curiosidad si había otras opciones en este sentido.

Respuesta

61

Subclases es la mejor opción.

Me subclase su principal clase genérica:

class BaseGeneric<T,U>

con una clase específica

class MyGeneric<T> : BaseGeneric<T, string>

Esto hace que sea fácil de mantener su lógica en un solo lugar (la clase base) , pero también es fácil de proporcionar ambas opciones de uso. Dependiendo de la clase, probablemente se necesita muy poco trabajo adicional para que esto suceda.

+1

ah ... eso tiene sentido.¿Se permite que el nombre de tipo sea el mismo si los parámetros de tipo proporcionan una firma única? – el2iot2

+2

@ee: sí, los genéricos son 'overloadable' por parámetro count. –

+0

@ee: Sí, pero sería cauteloso de hacer eso. Es "legal" en .NET hacerlo, pero puede generar confusión. Prefiero que el nombre del tipo de cadena derivada sea similar a la clase genérica principal (por lo que es obvio qué es/fácil de encontrar), pero un nombre que hace que sea obvio que es una cadena. –

6

C# no es compatible con esta característica.

Como dijiste, puedes crear una subclase (si no está sellada, y duplicar todas las declaraciones de los constructores) pero es algo completamente diferente.

1

Desafortunadamente C# no es compatible con lo que está tratando de hacer. Sería una característica difícil de implementar dado que el tipo predeterminado para un parámetro tendría que cumplir con las restricciones genéricas y muy probablemente crearía dolores de cabeza cuando el CLR intentara garantizar la seguridad del tipo.

+1

No realmente. Se podría haber hecho con un atributo (como los parámetros por defecto en VB.NET) y hacer que el compilador lo reemplace en tiempo de compilación. La razón principal son los objetivos de diseño de C#. –

+0

El compilador debe asegurarse de que el parámetro predeterminado satisfaga las restricciones genéricas. Además, el parámetro predeterminado sería una restricción genérica en sí misma porque cualquier suposición sobre el parámetro tipo en el método requeriría que cualquier parámetro de tipo no predeterminado herede de él. –

+0

@Andrew, el parámetro predeterminado no necesita ser una restricción genérica. Si esto llegara a comportarse más como los parámetros de plantilla por defecto en C++ y luego extendiendo a la clase de automatonic sería perfectamente bien hacer: MiPlantilla x = null Debido T2 no tiene restricciones genéricas, por lo flotador está bien a pesar del tipo predeterminado de cuerda . De esta forma, los parámetros predeterminados de la plantilla son esencialmente solo "azúcar sintáctico" para escribir MyTemplate como abreviatura de MyTemplate . –

13

Una solución es la subclasificación. Otro que usaría en su lugar, son los métodos de fábrica (combinados con la palabra clave var).

public class MyTemplate<T1,T2> 
{ 
    public MyTemplate(..args..) { ... } // constructor 
} 

public static class MyTemplate{ 

    public static MyTemplate<T1,T2> Create<T1,T2>(..args..) 
    { 
     return new MyTemplate<T1, T2>(... params ...); 
    } 

    public static MyTemplate<T1, string> Create<T1>(...args...) 
    { 
     return new MyTemplate<T1, string>(... params ...); 
    } 
} 

var val1 = MyTemplate.Create<int,decimal>(); 
var val2 = MyTemplate.Create<int>(); 

En el ejemplo val2 anterior es de tipo MyTemplate<int,string>y no un tipo derivado de ella.

Un tipo class MyStringTemplate<T>:MyTemplate<T,string> no es del mismo tipo que MyTemplate<T,string>. Esto podría plantear algunos problemas en ciertos escenarios. Por ejemplo, no puede convertir una instancia de MyTemplate<T,string> en MyStringTemplate<T>.

+3

Este es el enfoque más útil. Muy buena solución –

8

También puede crear una sobrecarga de clase como tal

public class MyTemplate<T1, T2> { 
    public T1 Prop1 { get; set; } 
    public T2 Prop2 { get; set; } 
} 

public class MyTemplate<T1> : MyTemplate<T1, string>{} 
+0

Lea otras respuestas antes de publicar una respuesta tardía, porque probablemente su solución sea la misma que la de los demás. –

+4

la respuesta aceptada fue crear una clase con un nombre diferente, mi solución es Sobrecargar la misma clase – Moes

+1

No, ambos están creando una nueva clase. El nombre no importa aquí. 'MyTemplate ' es una clase diferente de 'MyTemplate ', ni 'AnotherTemplate '. –

Cuestiones relacionadas