简体   繁体   English

切换大小写和泛型检查

[英]Switch case and generics checking

I want to write a function that format int and decimal differently into string我想编写一个函数,将intdecimal不同的方式格式化为字符串

I have this code:我有这个代码:

and I want to rewrite it to generics:我想将其重写为泛型:

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

How can i use T in the function body?如何在函数体中使用 T?

What syntax should I use?我应该使用什么语法?

You might use TypeCode for switch:您可以使用TypeCode进行切换:

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

In modern C#:在现代 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}";
    }
}

Another way to do switch on generic is:另一种打开泛型的方法是:

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

Note that when as a case guard in switch expressions was introduced in C# 7.0 /Visual Studio 2017.需要注意的是when在一个外壳安全switch表达式在C#7.0中引入/ Visual Studio的2017年。

Edit: If you only want to handle exactly int and double, just have two overloads:编辑:如果您只想精确处理 int 和 double,只需有两个重载:

DoFormat(int value)
{
}

DoFormat(double value)
{
}

If you insist on using generics:如果你坚持使用泛型:

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

OR或者

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

I had a similar question, but with custom classes rather than built-in data types.我有一个类似的问题,但使用自定义类而不是内置数据类型。 Here's how I went about it:以下是我的处理方式:

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

I modified it to use the types you are using (ie, int and decimal).我修改它以使用您正在使用的类型(即,int 和decimal)。 I like this approach more than hard coding strings, as a refactor of a class name will not break this code.我比硬编码字符串更喜欢这种方法,因为类名的重构不会破坏这段代码。

With newer versions of C#, you could also do this some of the time:使用较新版本的 C#,您有时也可以这样做:

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

I say "some of the time" because that would only really work with types that have a default constructor.我说“有时”是因为那只适用于具有默认构造函数的类型。 This approach uses pattern matching and discards.这种方法使用模式匹配和丢弃。 I don't really like it since you need to create an instance of the object (that you then throw away) and because of the default constructor requirement.我真的不喜欢它,因为您需要创建对象的实例(然后将其丢弃)并且因为默认构造函数要求。

more formatted way to do switch on generic is:开启泛型的更格式化的方法是:

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

In C# 8 you can use (replace "..." with the relevant code):C# 8 中,您可以使用(用相关代码替换“...”):

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

Another elegant option (replace "..." with the relevant code):另一个优雅的选择(用相关代码替换“...”):

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

For more info: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression有关更多信息: https : //docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression

Alternatively you could always do:或者,您可以随时执行以下操作:

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

    return string.Join(", ", itemArray);
}

You could check the type of the variabele;您可以检查变量的类型;

    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?
    }

You could instead of using generics use IConvertible你可以代替使用泛型使用 IConvertible

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM