2013-08-12 18 views
5

Desidero scrivere una classe generica che dovrebbe funzionare con i tipi byte e ushort. Quale vincolo dovrei usare per questa classe? Come posso rilevare la proprietà MaxValue all'interno di questa classe?Rileva MaxValue del parametro generico

class MyClass<T> // where T: ??? 
{ 
    void Foo() 
    { 
     int maxValue = T.MaxValue; // how can I do this? 
    } 
} 

Se la classe è stato creato con il tipo inaspettata, che non contiene proprietà MaxValue, non mi interessa - per esempio, posso buttare un'eccezione in fase di esecuzione.

+0

Utilizzare un interruttore caso, nessun altro modo. poiché oltre ai tipi primitivi non esiste il concetto di MaxValue –

risposta

5

Un modo sarebbe di sfruttare la nuova dynamic parola chiave:

void Main() 
{ 
    Test(10); 
    Test(10.234); 
    Test((Byte)42); 
    Test(true); 
} 

public void Test<T>(T value) 
    where T : struct 
{ 
    T maxValue = MaxValue((dynamic)value); 
    maxValue.Dump(); 
} 

public int MaxValue(int dummy) 
{ 
    return int.MaxValue; 
} 

public double MaxValue(double dummy) 
{ 
    return double.MaxValue; 
} 

public byte MaxValue(byte dummy) 
{ 
    return byte.MaxValue; 
} 

public object MaxValue(object dummy) 
{ 
    // This method will catch all types that has no specific method 
    throw new NotSupportedException(dummy.GetType().Name); 
} 

Oppure, si potrebbe utilizzare la riflessione per ottenere il campo MaxValue:

void Main() 
{ 
    Test(10); 
    Test(10.234); 
    Test((Byte)42); 
    Test(true); 
} 

public void Test<T>(T value) 
    where T : struct 
{ 
    FieldInfo maxValueField = typeof(T).GetField("MaxValue", BindingFlags.Public 
     | BindingFlags.Static); 
    if (maxValueField == null) 
     throw new NotSupportedException(typeof(T).Name); 
    T maxValue = (T)maxValueField.GetValue(null); 
    maxValue.Dump(); 
} 

È possibile testare questi due programmi tramite LINQPad.

2

È possibile utilizzare solo struct come vincolo che consentirà solo tipi di valore per T. Ogni tipo di valore specifico come un vincolo verrà rifiutato dal compilatore. Quindi devi eseguire un controllo di runtime se lo T è uno dei tipi consentiti.

L'unico modo per ottenere il MaxValue del vostro (sconosciuto) di tipo T è riflessione con qualcosa di simile:

typeof(T).GetField("MaxValue").GetValue(null); 
+0

a destra. considerando il controllo, potrebbe essere meglio evitare il costo della riflessione e semplicemente passare al caso (typeof (T) .FullName) "System.Int32": Int.MaxValue; e così via – citykid

+1

E dovrebbe essere possibile unbox a 'T', quindi' var maxValue = (T) typeof (T) .GetField ("MaxValue"). GetValue (null, null); '. –

+0

@citykid, Reflection non dovrebbe essere evitato a tutti i costi; dipende da dove viene effettuato il controllo. Se è fatto a livello meta o tipo, non è così costoso. – toddmo

0

bene, non ci sono vincoli per questo, come ho concluso da here e alcuni altri luoghi ho letto.

hoever, è possibile avvolgere l'ushort e di byte utilizzando un'interfaccia:

public interface IReturnUShortAndBytes 
{ 
    ushort ReturnUShortsOrZero(); 

    byte ReturnByteOrZero(); 
} 

non è la cosa migliore, ma potrebbe fare il lavoro, dipende da quello che ti serve

3

provare qualcosa di simile

public T GetMaxValue() 
    { 
     object maxValue = default(T); 
     TypeCode typeCode = Type.GetTypeCode(typeof(T)); 
     switch (typeCode) 
     { 
      case TypeCode.Byte: 
       maxValue = byte.MaxValue; 
       break; 
      case TypeCode.Char: 
       maxValue = char.MaxValue; 
       break; 
      case TypeCode.DateTime: 
       maxValue = DateTime.MaxValue; 
       break; 
      case TypeCode.Decimal: 
       maxValue = decimal.MaxValue; 
       break; 
      case TypeCode.Double: 
       maxValue = decimal.MaxValue; 
       break; 
      case TypeCode.Int16: 
       maxValue = short.MaxValue; 
       break; 
      case TypeCode.Int32: 
       maxValue = int.MaxValue; 
       break; 
      case TypeCode.Int64: 
       maxValue = long.MaxValue; 
       break; 
      case TypeCode.SByte: 
       maxValue = sbyte.MaxValue; 
       break; 
      case TypeCode.Single: 
       maxValue = float.MaxValue; 
       break; 
      case TypeCode.UInt16: 
       maxValue = ushort.MaxValue; 
       break; 
      case TypeCode.UInt32: 
       maxValue = uint.MaxValue; 
       break; 
      case TypeCode.UInt64: 
       maxValue = ulong.MaxValue; 
       break; 
      default: 
       maxValue = default(T);//set default value 
       break; 
     } 

     return (T)maxValue;        
    } 
+0

Grazie per l'idea GetTypeCode - davvero utile per la scrittura generici di calcolo. –

0

Questo vincolo non è possibile in C#. È possibile vincolare a tipi di valore con interfacce specifiche, ad esempio

where T : struct, IComparable, IFormattable, 
    IConvertible, IComparable<T>, IEquatable<T> 

Sfortunatamente questo corrisponde a più tipi di quelli che si desidera. E lo MaxValue non è membro di alcuna interfaccia (è un campo!), Quindi il vincolo non ti aiuterà qui. Potresti voler usare la riflessione come nella risposta di Fero.

Problemi correlati