.NET Framework中是否存在检查值是否适合某种类型的内容?

时间:2022-02-18 19:16:58

I need to find out if a decimal value will fit into a type (the destination type is detected at runtime) and truncate it to its max or min value if not so I can send it thru the network.

我需要找出一个十进制值是否适合一个类型(在运行时检测到目标类型)并将其截断为最大值或最小值,如果不是这样我可以通过网络发送它。

I would like to avoid big switch sentences with types and I thought that maybe there is already something in the .NET Framework.

我想避免使用类型的大切换句子,我想可能已经在.NET Framework中有了一些东西。

2 个解决方案

#1


This action has a name in signal processing: clipping.

此操作在信号处理中有一个名称:剪辑。

And here there is the totally useless DecimalRestrictor<T>, based on a dinamically built Expression Tree in the form

这里有完全没用的DecimalRestrictor ,基于表格中的dinamically构建表达式树

x => x <= min ? min : x >= max ? max : (T)x;

plus an exception for decimal, float and double: all the three types can accept any decimal value.

加上decimal,float和double的例外:这三种类型都可以接受任何十进制值。

The code:

public static class DecimalClipper<T>
{
    public static readonly Func<decimal, T> Clip;

    static DecimalClipper()
    {
        ParameterExpression value = Expression.Parameter(typeof(decimal), "value");

        Expression<Func<decimal, T>> lambda;

        if (typeof(T) == typeof(decimal))
        {
            lambda = Expression.Lambda<Func<decimal, T>>(value, value);
        }
        else if (typeof(T) == typeof(float) || typeof(T) == typeof(double))
        {
            lambda = Expression.Lambda<Func<decimal, T>>(Expression.Convert(value, typeof(T)), value);
        }
        else
        {
            T min = (T)typeof(T).GetField("MinValue", BindingFlags.Static | BindingFlags.Public).GetValue(null);
            Expression minT = Expression.Constant(min);
            Expression minDecimal = Expression.Constant(Convert.ToDecimal(min));

            T max = (T)typeof(T).GetField("MaxValue", BindingFlags.Static | BindingFlags.Public).GetValue(null);
            Expression maxT = Expression.Constant(max);
            Expression maxDecimal = Expression.Constant(Convert.ToDecimal(max));

            UnaryExpression cast = Expression.Convert(value, typeof(T));
            ConditionalExpression greaterThanOrEqual = Expression.Condition(Expression.GreaterThanOrEqual(value, maxDecimal), maxT, cast);
            ConditionalExpression lesserThanOrEqual = Expression.Condition(Expression.LessThanOrEqual(value, minDecimal), minT, greaterThanOrEqual);

            lambda = Expression.Lambda<Func<decimal, T>>(lesserThanOrEqual, value);
        }

        Clip = lambda.Compile();
    }
}

public static class DecimalEx
{
    public static T Clip<T>(this decimal value)
    {
        return DecimalClipper<T>.Clip(value);
    }
}

I'm even including an extension method...

我甚至包括一个扩展方法......

Examples of use:

使用示例:

int i1 = decimal.MaxValue.Clip<int>();
int i2 = decimal.MinValue.Clip<int>();
int i3 = 5.5M.Clip<int>();
int i4 = -5.5M.Clip<int>();
byte i5 =(-5.5M).Clip<byte>();
//char i6 = decimal.MaxValue.Clip<char>();
float i7 = decimal.MaxValue.Clip<float>();
double i8 = decimal.MaxValue.Clip<double>();
decimal i9 = decimal.MaxValue.Clip<decimal>();

Ah... the expression tree is generated only once for each type T used and then cached thanks to the working of generic types and static members.

啊...表达式树只为每个使用的类型T生成一次,然后由于泛型类型和静态成员的工作而缓存。

The char, IntPtr, UIntPtr aren't supported at this time.

目前不支持char,IntPtr,UIntPtr。

#2


that would be my solution;

这将是我的解决方案;

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal value = 123456.789M;

            Console.WriteLine(ConvertOrMinMax<Byte>(value));
            Console.WriteLine(ConvertOrMinMax<Int16>(value));
            Console.WriteLine(ConvertOrMinMax<Int32>(value));
            Console.WriteLine(ConvertOrMinMax<Int64>(value));
            Console.WriteLine(ConvertOrMinMax<Decimal>(value));
            Console.WriteLine(ConvertOrMinMax<Double>(value));
            Console.WriteLine(ConvertOrMinMax<float>(value));

            Console.Read();
        }

        static T ConvertOrMinMax<T>(decimal v)
        {
            var myType = typeof(T);

            if(myType == typeof(double) || myType == typeof(float))
                return (T)Convert.ChangeType(v, myType);

            decimal min = (decimal)Convert.ChangeType(myType.GetField("MinValue").GetValue(null), typeof(decimal));

            if (v < min)
                return (T)Convert.ChangeType(min, myType);

            decimal max = (decimal)Convert.ChangeType(myType.GetField("MaxValue").GetValue(null), typeof(decimal)); ;

            if (v > max)
                return (T)Convert.ChangeType(max, myType);

            return (T)Convert.ChangeType(v, myType);
        }
    }
}

#1


This action has a name in signal processing: clipping.

此操作在信号处理中有一个名称:剪辑。

And here there is the totally useless DecimalRestrictor<T>, based on a dinamically built Expression Tree in the form

这里有完全没用的DecimalRestrictor ,基于表格中的dinamically构建表达式树

x => x <= min ? min : x >= max ? max : (T)x;

plus an exception for decimal, float and double: all the three types can accept any decimal value.

加上decimal,float和double的例外:这三种类型都可以接受任何十进制值。

The code:

public static class DecimalClipper<T>
{
    public static readonly Func<decimal, T> Clip;

    static DecimalClipper()
    {
        ParameterExpression value = Expression.Parameter(typeof(decimal), "value");

        Expression<Func<decimal, T>> lambda;

        if (typeof(T) == typeof(decimal))
        {
            lambda = Expression.Lambda<Func<decimal, T>>(value, value);
        }
        else if (typeof(T) == typeof(float) || typeof(T) == typeof(double))
        {
            lambda = Expression.Lambda<Func<decimal, T>>(Expression.Convert(value, typeof(T)), value);
        }
        else
        {
            T min = (T)typeof(T).GetField("MinValue", BindingFlags.Static | BindingFlags.Public).GetValue(null);
            Expression minT = Expression.Constant(min);
            Expression minDecimal = Expression.Constant(Convert.ToDecimal(min));

            T max = (T)typeof(T).GetField("MaxValue", BindingFlags.Static | BindingFlags.Public).GetValue(null);
            Expression maxT = Expression.Constant(max);
            Expression maxDecimal = Expression.Constant(Convert.ToDecimal(max));

            UnaryExpression cast = Expression.Convert(value, typeof(T));
            ConditionalExpression greaterThanOrEqual = Expression.Condition(Expression.GreaterThanOrEqual(value, maxDecimal), maxT, cast);
            ConditionalExpression lesserThanOrEqual = Expression.Condition(Expression.LessThanOrEqual(value, minDecimal), minT, greaterThanOrEqual);

            lambda = Expression.Lambda<Func<decimal, T>>(lesserThanOrEqual, value);
        }

        Clip = lambda.Compile();
    }
}

public static class DecimalEx
{
    public static T Clip<T>(this decimal value)
    {
        return DecimalClipper<T>.Clip(value);
    }
}

I'm even including an extension method...

我甚至包括一个扩展方法......

Examples of use:

使用示例:

int i1 = decimal.MaxValue.Clip<int>();
int i2 = decimal.MinValue.Clip<int>();
int i3 = 5.5M.Clip<int>();
int i4 = -5.5M.Clip<int>();
byte i5 =(-5.5M).Clip<byte>();
//char i6 = decimal.MaxValue.Clip<char>();
float i7 = decimal.MaxValue.Clip<float>();
double i8 = decimal.MaxValue.Clip<double>();
decimal i9 = decimal.MaxValue.Clip<decimal>();

Ah... the expression tree is generated only once for each type T used and then cached thanks to the working of generic types and static members.

啊...表达式树只为每个使用的类型T生成一次,然后由于泛型类型和静态成员的工作而缓存。

The char, IntPtr, UIntPtr aren't supported at this time.

目前不支持char,IntPtr,UIntPtr。

#2


that would be my solution;

这将是我的解决方案;

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal value = 123456.789M;

            Console.WriteLine(ConvertOrMinMax<Byte>(value));
            Console.WriteLine(ConvertOrMinMax<Int16>(value));
            Console.WriteLine(ConvertOrMinMax<Int32>(value));
            Console.WriteLine(ConvertOrMinMax<Int64>(value));
            Console.WriteLine(ConvertOrMinMax<Decimal>(value));
            Console.WriteLine(ConvertOrMinMax<Double>(value));
            Console.WriteLine(ConvertOrMinMax<float>(value));

            Console.Read();
        }

        static T ConvertOrMinMax<T>(decimal v)
        {
            var myType = typeof(T);

            if(myType == typeof(double) || myType == typeof(float))
                return (T)Convert.ChangeType(v, myType);

            decimal min = (decimal)Convert.ChangeType(myType.GetField("MinValue").GetValue(null), typeof(decimal));

            if (v < min)
                return (T)Convert.ChangeType(min, myType);

            decimal max = (decimal)Convert.ChangeType(myType.GetField("MaxValue").GetValue(null), typeof(decimal)); ;

            if (v > max)
                return (T)Convert.ChangeType(max, myType);

            return (T)Convert.ChangeType(v, myType);
        }
    }
}