8

I want to write generic class which should work with byte and ushort types. What constraint should I use for this class? How can I detect MaxValue property inside of this class?

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

If class was created with unexpected type, which doesn't contain MaxValue property, I don't care - for example, I can throw exception at runtime.

Alex F
  • 42,307
  • 41
  • 144
  • 212

5 Answers5

14

One way would be to leverage the new dynamic keyword:

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);
}

Or, you could use reflection to obtain the MaxValue field:

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();
}

You can test these two programs through LINQPad.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
7

Try something like this

    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;                             
    }
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
2

You can only use struct as a constraint which will only allow value types for T. Every specific value type as a constraint will be rejected by the compiler. So you have to do a runtime check whether T is one of your allowed types.

The only way to get the MaxValue of your (unknown) type T is reflection with something like this:

typeof(T).GetField("MaxValue").GetValue(null);
fero
  • 6,050
  • 1
  • 33
  • 56
  • right. considering the check, it might be best to avoid the cost of reflection and simply switch(typeof(T).FullName) case "System.Int32": Int.MaxValue; and so on – citykid Aug 12 '13 at 06:38
  • 1
    And it should be possible to unbox that to `T`, so `var maxValue = (T)typeof(T).GetField("MaxValue").GetValue(null, null);`. – Jeppe Stig Nielsen Aug 12 '13 at 06:47
  • @citykid, Reflection shouldn't be avoided at all costs; it depends on where the check is made. If it's made on the meta or type level, it's not that expensive. – toddmo Jul 15 '16 at 15:59
  • As a static variable it's almost as good as a constant:`static readonly T maxValue = (T)typeof(T).GetField("MaxValue").GetValue(null);` – tombola Sep 13 '17 at 14:33
0

well, there is no constrains for that, as i concluded from here and some other places i've read.

hoever, you can wrap the ushort and byte by using an interface:

public interface IReturnUShortAndBytes
{
  ushort ReturnUShortsOrZero();

  byte ReturnByteOrZero();
}

it's not the best thing but it might do the work, depend on what you need

Community
  • 1
  • 1
No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
0

That constraint is not possible in C#. You can constrain to value types with specific interfaces, like

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

Unfortunately this will match more types than those you want. And the MaxValue is not member of any interface (it is a field!), so the constraint won't help you here. You may want to use reflection as in fero's answer.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181