切换案例和泛型检查

Ela*_*nda 17 c# generics

我想写一个格式化的函数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);
    }
Run Code Online (Sandbox Code Playgroud)

我如何在函数体中使用T?

我应该使用什么语法?

Nik*_*vić 38

您可以使用TypeCode进行切换:

switch (Type.GetTypeCode(typeof(T)))
{
    case TypeCode.Int32:
       break;
    case TypeCode.Decimal:
       break;
}
Run Code Online (Sandbox Code Playgroud)

  • 用户类型怎么样? (26认同)
  • 当你有“T”而不是“obj”时,你会如何使用第二种模式?(即,当您知道该类型并且没有该类型的实例时)。 (14认同)

fla*_*am3 27

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

switch (typeof(T))
{
    case Type intType when intType == typeof(int):
        ...
    case Type decimalType when decimalType == typeof(decimal):
        ...
    default:
        ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,在 C# 7.0 /Visual Studio 2017 中引入whenswitch表达式中的 case 保护


Nic*_*tby 18

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

switch (typeof(T).Name)
{
    case nameof(Int32):
        break;
    case nameof(Decimal):
        break;
}
Run Code Online (Sandbox Code Playgroud)

我修改它以使用您正在使用的类型(即 int 和decimal)。与硬编码字符串相比,我更喜欢这种方法,因为类名的重构不会破坏此代码。

使用较新版本的 C#,您有时也可以执行此操作:

switch (Activator.CreateInstance(typeof(T)))
{
    case int _:
        break;
    case decimal _:
        break;
}
Run Code Online (Sandbox Code Playgroud)

我说“有时”是因为这只适用于具有默认构造函数的类型。该方法使用模式匹配和丢弃。我不太喜欢它,因为您需要创建对象的实例(然后将其丢弃)并且由于默认构造函数的要求。


Tam*_*ely 11

在现代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}";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 纠正我自己,default(T) 解决方案不适用于 ref 类型,因为默认值为 null。因此,您必须测试该类型,或者可能只是找到更好的设计。 (7认同)
  • 如果我只得到T但没有得到T的值怎么办?说公共T Get &lt;T&gt;(字符串名称){} (6认同)
  • 您可以使用`default(T)`。但我不确定这是否比拥有带有键类型的字典更快。如果您想要的是返回不同类型的键控集合,只需将值保留为公共基类型(或对象),然后在 get 中直接强制转换,或者使用返回 null 的 `as`。这是完美的行为,进行类型检查不会为您节省任何代码,只会使错误处理复杂化。 (4认同)

pal*_*ota 9

如果您有对象,则可以使用 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,
    };
Run Code Online (Sandbox Code Playgroud)

基准

方法 时间
三元If 0.37纳秒
真开关 0.37纳秒
默认开关 0.48纳秒
When_Switch 1.92纳秒
类型代码开关 3.85纳秒
何时切换 3.96纳秒
交换机名称 7.98纳秒
激活开关 12.10纳秒


Sim*_*Var 6

编辑:如果您只想精确处理 int 和 double,则只需两个重载:

DoFormat(int value)
{
}

DoFormat(double value)
{
}
Run Code Online (Sandbox Code Playgroud)

如果您坚持使用泛型:

switch (value.GetType().Name)
{
    case "Int32":
        break;
    case "Double":
        break;
    default:
        break;
}
Run Code Online (Sandbox Code Playgroud)

或者

if (value is int)
{
    int iValue = (int)(object)value;
}
else if (value is double)
{
    double dValue = (double)(object)value;
}
else
{
}
Run Code Online (Sandbox Code Playgroud)


Ing*_*n29 6

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:
        ...
}
Run Code Online (Sandbox Code Playgroud)

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

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'?
    _ => ...,
};
Run Code Online (Sandbox Code Playgroud)


sht*_*se8 5

切换通用的更格式化的方法是:

switch (true)
{
    case true when typeof(T) == typeof(int):
        ...
    case true when typeof(T) == typeof(decimal):
        ...
    default:
        ...
}
Run Code Online (Sandbox Code Playgroud)