8

我想编写应该使用byteushort类型的通用类。我应该对这个类使用什么约束?如何检测MaxValue此类内部的属性?

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

如果类是用不包含 MaxValue 属性的意外类型创建的,我不在乎 - 例如,我可以在运行时抛出异常。

4

5 回答 5

13

一种方法是利用 newdynamic关键字:

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

或者,您可以使用反射来获取 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();
}

您可以通过LINQPad测试这两个程序。

于 2013-08-12T06:41:18.640 回答
7

尝试这样的事情

    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;                             
    }
于 2013-08-12T06:42:59.857 回答
2

您只能将struct其用作仅允许T. 作为约束的每个特定值类型都将被编译器拒绝。所以你必须做一个运行时检查是否T是你允许的类型之一。

MaxValue获得您的(未知)类型的唯一方法T是反射,如下所示:

typeof(T).GetField("MaxValue").GetValue(null);
于 2013-08-12T06:29:45.737 回答
0

该约束在 C# 中是不可能的。您可以使用特定接口限制值类型,例如

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

不幸的是,这将匹配比您想要的更多的类型。并且MaxValue不是任何接口的成员(它是一个字段!),所以约束在这里对你没有帮助。您可能想在fero的回答中使用反射。

于 2013-08-12T06:44:22.413 回答
0

好吧,这没有任何限制,正如我从这里和我读过的其他一些地方得出的结论。

但是,您可以使用接口包装 ushort 和 byte:

public interface IReturnUShortAndBytes
{
  ushort ReturnUShortsOrZero();

  byte ReturnByteOrZero();
}

这不是最好的事情,但它可能会起作用,这取决于你需要什么

于 2013-08-12T06:31:09.723 回答