2010-11-08 11 views
13

¿Hay una manera de proporcionar un tipo predeterminado para un parámetro T de un genérico, algo así como:De todos modos a un parámetro genérico por defecto a un cierto tipo?

class Something<T = string> 
{ 
} 

Yo sé que no hay muchas razones de peso para esto, pero me gustaría hacer alusión al cliente de código qué tipo debería usar preferiblemente.

Otra cosa, ¿puedo restringir el tipo genérico a ValueType? Acabo de ver que no puedes, pero aún así, me gustaría saber por qué. Alguien tiene una pista?

Gracias!

+0

Este no es posible por defecto. – Vercas

+1

¿Por qué dice que no puede restringir un tipo genérico a un tipo de valor cuando casi todas las respuestas aquí demuestran cómo se hace? (No a través de 'ValueType', sino usando la palabra clave' struct'.) – stakx

+0

@stakx Lo dije de manera predeterminada. (Como lo intentó, "por defecto" el valor.) – Vercas

Respuesta

18

Ok, supongamos que tiene la clase:

class Something<T> 
{ 

} 

Ahora, es posible que desee otra clase:

class Something : Something<string> 
{ 
    // NO MORE CODE NEEDED HERE! 
} 

Ésta es la única y la mejor manera.
Entonces, si uno usa Something, realmente usará Something<string>.

+2

Esto funciona (fsvo "funciona", no es que lo recomiende en general) porque 'Something' y' Something <'> '(y' Something <','> 'es diferente) son dos * clases * diferentes (imagine el caso de' system.collections.IEnumerable 'y' systems.collections.generic.IEnumerable '- esto difiere de Java donde esencialmente solo se permite un tipo" colapsado "). Por otro lado, ahora tiene dos tipos * diferentes * :-) –

+0

Otra alternativa puede ser: 'using Something = foo.Something ;' Sin embargo, el constructo de uso solo está disponible en algunos casos (antes de las clases o en la parte superior de una clase externa antes de miembros, etc.) y * no está expuesta externamente * como un tipo/alias. –

+0

@pst Lo usaría en lugar de lo que publiqué, pero pensé que podría necesitarlo más. – Vercas

3

Puede utilizar la palabra clave where para restringir los tipos específicos que se pueden usar como parámetros de tipo.

Por ejemplo, usted podría su clase para aceptar sólo los parámetros de tipo genérico donde el tipo implementa la interfaz IComparable:

class Something<T> where T : IComparable 
{ 
} 

O, como usted ha mencionado, puede restringir T ser un tipo de valor mediante el uso de where T : struct : artículo

class Something<T> where T : struct 
{ 
} 

Sede de MSDN en Constraints on Type Parameters para obtener más información. ¡Espero que esto ayude!

2

De acuerdo con la docs puede restringir T ser un tipo de valor mediante el where palabra clave

where T: struct 

Declaración de clase sería el siguiente aspecto:

class Something<T> where T: struct { 
    ... 
} 

Aunque string no es un tipo de valor y no podrá usarlo con tal restricción. Tal vez IComparable sería mejor en caso de que también desee utilizar el tipo string.

En cuanto a especificar el tipo predeterminado, no creo que sea posible.

0
class Something<T> where T : string 
{ 
}; // eo class Something<> 
+0

No se puede heredar de la cadena por lo que la única opción sería declarar 'var s = new Something ;'. Todo lo demás se convertirá en un error. – Vercas

2

No creo que haya una manera de predeterminarlo a cierto tipo, pero podría ponerlo como un comentario en los documentos XML. En cuanto a la restricción a un tipo de valor, puede obtener este comportamiento declarando su genérico de la siguiente manera:

class MyGeneric<T> where T : struct 
{ 
    ... 
} 
+0

Y +1 para responder la 2da pregunta: p –

+1

Si quiere cadenas, puede necesitar 'donde T: clase' porque' System.String' es una clase. – Vercas

+0

@Vercas - Corrija o obtendrá el error: 'El tipo 'cadena' debe ser un tipo de valor que no admite nulos para usarlo como parámetro 'T' en el tipo genérico o método 'Algo ' ' – atconway

0

Necesita una subclase.Recientemente necesitaba algo por el estilo, esto es mi solución:

public abstract class MyGenericClass<T1, T2> 
    { 
     public abstract void Do(T1 param1, T2 param2); 
    } 

    public class Concrete : MyGenericClass<string, int?> 
    {   
     public override void Do(string param1, int? param2 = null) 
     { 
      Console.WriteLine("param1: {0}", param1); 

      if (param2 == null) 
       Console.WriteLine("param2 == null"); 
      else 
       Console.WriteLine("param2 = {0}", param2); 

      Console.WriteLine("============================================="); 
     }   
    } 

Usted puede llamar al método:

string param1 = "Hello"; 
    Concrete c = new Concrete(); 
    c.Do(param1); 
    c.Do(param1, 123); 
    c.Do(param1, (int?)null); 
    /* Result: 
    param1: Hello 
    param2 == null 
    ============================================= 
    param1: Hello 
    param2 = 123 
    ============================================= 
    param1: Hello 
    param2 == null 
    ============================================= 
    */ 

Yo prefiero usar los valores por defecto nulos desde que leí esto: C# In Depth – Optional Parameters and Named Arguments

Cuestiones relacionadas