切换大小写和泛型检查

本文关键字:泛型 检查 大小写 | 更新日期: 2023-09-27 18:28:42

我想编写一个函数,将intdecimal以不同的方式格式化为字符串

我有这个代码:

我想将其重写为泛型:

    public static string FormatAsIntWithCommaSeperator(int value)
    {
        if (value == 0 || (value > -1 && value < 1))
            return "0";
        return String.Format("{0:#,###,###}", value);
    }
    public static string FormatAsDecimalWithCommaSeperator(decimal value)
    {
        return String.Format("{0:#,###,###.##}", value);
    }

    public static string FormatWithCommaSeperator<T>(T value) where T : struct
    {
        string formattedString = string.Empty;
        if (typeof(T) == typeof(int))
        {
            if ((int)value == 0 || (value > -1 && value < 1))
            return "0";
            formattedString = String.Format("{0:#,###,###}", value);
        }
        //some code...
    }
    /// <summary>
    /// If the number is an int - returned format is without decimal digits
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string FormatNumberTwoDecimalDigitOrInt(decimal value)
    {
        return (value == (int)value) ? FormatAsIntWithCommaSeperator(Convert.ToInt32(value)) : FormatAsDecimalWithCommaSeperator(value);
    }

如何在函数体中使用 T?

我应该使用什么语法?

切换大小写和泛型检查

您可以使用 TypeCode 枚举进行切换:

switch (Type.GetTypeCode(typeof(T)))
{
    case TypeCode.Int32:
       ...
       break;
    case TypeCode.Decimal:
       ...
       break;
}

从 C# 7.0 开始,可以使用模式匹配:

switch (obj)
{
    case int i:
       ...
       break;
    case decimal d:
       ...
       break;
    case UserDefinedType u:
       ...
       break;
}

从 C# 8.0 开始,可以使用开关表达式:

string result = obj switch {
    int i => $"Integer {i}",
    decimal d => $"Decimal {d}",
    UserDefinedType u => "User defined {u}",
    _ => "unexpected type"
};

另一种打开泛型的方法是:

switch (typeof(T))
{
    case Type intType when intType == typeof(int):
        ...
    case Type decimalType when decimalType == typeof(decimal):
        ...
    default:
        ...
}

请注意,switch表达式中作为案例防护的when是在 C# 7.0/Visual Studio 2017 中引入的。

在现代 C# 中:

public static string FormatWithCommaSeperator<T>(T value) where T : struct
{
    switch (value)
    {
        case int i:
            return $"integer {i}";
        case double d:
            return $"double {d}";
    }
}

我有一个类似的问题,但使用自定义类而不是内置数据类型。我是这样去做的:

switch (typeof(T).Name)
{
    case nameof(Int32):
        break;
    case nameof(Decimal):
        break;
}

我修改了它以使用您正在使用的类型(即 int 和十进制(。我更喜欢这种方法而不是硬编码字符串,因为类名的重构不会破坏此代码。

对于较新版本的 C#,有时也可以执行此操作:

switch (Activator.CreateInstance(typeof(T)))
{
    case int _:
        break;
    case decimal _:
        break;
}

我说"某些时候",因为这仅适用于具有默认构造函数的类型。此方法使用模式匹配和丢弃。我不太喜欢它,因为您需要创建对象的实例(然后丢弃(并且由于默认构造函数要求。

编辑:如果你只想处理整数和双精度,只需有两个重载:

DoFormat(int value)
{
}
DoFormat(double value)
{
}

如果您坚持使用泛型:

switch (value.GetType().Name)
{
    case "Int32":
        break;
    case "Double":
        break;
    default:
        break;
}

if (value is int)
{
    int iValue = (int)(object)value;
}
else if (value is double)
{
    double dValue = (double)(object)value;
}
else
{
}
打开

泛型的更格式化的方法是:

switch (true)
{
    case true when typeof(T) == typeof(int):
        ...
    case true when typeof(T) == typeof(decimal):
        ...
    default:
        ...
}

从 C# 8 开始,可以这样做,这也适用于 Nullable:

switch ((Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T)).Name)
{
    case nameof(Int32):
        ...
    case nameof(Decimal):
        ...
    case nameof(Boolean):  // You can also switch types like 'bool' or Nullable 'bool?'
        ...
    case nameof(String):   // Why not to use 'string'?
        ...
    default:
        ...
}

如果您更喜欢切换表达式,可以使用:

return (Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T)).Name switch
{
    nameof(Int32) => ...,
    nameof(Decimal) => ...,
    nameof(Boolean) => ...,  // You can also switch types like 'bool' or Nullable 'bool?'
    nameof(String) => ...,   // Why not to use 'string'?
    _ => ...,
};

如果有对象,可以使用 C# 7 模式匹配。但是,如果您没有对象并且想要打开泛型类型 T,那么最好和最快的解决方案只是三元 if 运算符。

public string TernaryIf<T>() =>
    typeof(T) == typeof(int) ? "#,###,###" :
    typeof(T) == typeof(decimal) ? "#,###,###.##" :
    null;
public string TrueSwitch<T>() =>
    true switch
    {
        true when typeof(T) == typeof(int) => "#,###,###",
        true when typeof(T) == typeof(decimal) => "#,###,###.##",
        _ => null,
    };
public string DefaultSwitch<T>() =>
    default(T) switch
    {
        int => "#,###,###",
        decimal => "#,###,###.##",
        _ => null,
    };
public string When_Switch<T>() =>
    typeof(T) switch
    {
        Type _ when typeof(T) == typeof(int) => "#,###,###",
        Type _ when typeof(T) == typeof(decimal) => "#,###,###.##",
        _ => null,
    };
public string TypeCodeSwitch<T>() =>
    Type.GetTypeCode(typeof(T)) switch
    {
        TypeCode.Int32 => "#,###,###",
        TypeCode.Decimal => "#,###,###.##",
        _ => null,
    };
public string WhenSwitch<T>() =>
    typeof(T) switch
    {
        Type intType when intType == typeof(int) => "#,###,###",
        Type decimalType when decimalType == typeof(decimal) => "#,###,###.##",
        _ => null,
    };
public string NameOfSwitch<T>() =>
    typeof(T).Name switch
    {
        nameof(Int32) => "#,###,###",
        nameof(Decimal) => "#,###,###.##",
        _ => null,
    };
public string ActivatorSwitch<T>() =>
    Activator.CreateInstance(typeof(T)) switch
    {
        int => "#,###,###",
        decimal => "#,###,###.##",
        _ => null,
    };

基准

<样式>方法
时间
三元如果0.37 纳秒
TrueSwitch0.37 纳秒
默认开关0.48 纳秒
When_Switch1.92 纳秒
TypeCodeSwitch3.85 纳秒
WhenSwitch3.96 纳秒
NameOfSwitch7.98 纳秒
激活器开关12.10 纳秒
或者,

您可以随时执行以下操作:

public static string FormatWithCommaSeparator<T>(T[] items)
{
    var itemArray = items.Select(i => i.ToString());
    return string.Join(", ", itemArray);
}

您可以检查变量的类型;

    public static string FormatWithCommaSeperator<T>(T value)
    {
        if (value is int)
        {
            // Do your int formatting here
        }
        else if (value is decimal)
        {
            // Do your decimal formatting here
        }
        return "Parameter 'value' is not an integer or decimal"; // Or throw an exception of some kind?
    }

您可以使用 IConvertible 代替泛型

    public static string FormatWithCommaSeperator(IConvertible value)
    {
            IConvertible convertable = value as IConvertible;
            if(value is int)
            {
                int iValue = convertable.ToInt32(null);
                //Return with format.
            }
            .....
    }

在 C# 8 中,您可以使用(替换"...",并附上相关代码(:

... type switch
{
    Type _ when type == typeof(int) => ...,
    Type _ when type == typeof(decimal) => ...,
    _ => ... // default case
};

另一个优雅的选项(替换"...",并附上相关代码(:

... Type.GetTypeCode(type) switch
{
    TypeCode.Int32 => ...,
    TypeCode.Decimal => ...,
    _ => ...
};

欲了解更多信息:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression