2015-05-11 63 views
2

我需要找出decimal值是否适合某种类型(在运行时检测到目标类型),如果不是,则将其截断为最大值或最小值,以便我可以通过网络发送它。.NET Framework中是否有某些东西来检查某个值是否适合某种类型?

我想避免与类型的大开关句子,我想可能已经有一些在.NET Framework中。

+1

您是如何获得价值的?它是否有其他类型或文本? –

+0

它是存储该值的小数。在问题中添加,谢谢 –

+0

所以,你想把它放在最小的类型,将举行? –

回答

5

此操作在信号处理中有一个名称:clipping

而这里是完全无用DecimalRestrictor<T>,基于形式

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

一个dinamically内置表达式树加上decimalfloatdouble一个例外:所有的三种类型可以接受任何decimal值。

的代码:

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

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

实例:

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

嗯...仅产生的表达式树一次为每种类型T使用,然后缓存感谢泛型类型和静态成员的工作。

目前不支持charIntPtrUIntPtr

+0

这是线程安全吗?如果没有,只是为了让它线程安全:) – Fredou

+0

@Fredou唯一的非线程安全的时刻可能是初始化(静态构造函数),但这是保证线程安全的clr。因此,尽可能多的线程安全,因为你可以拥有一些东西。嗯有人可以有'struct MyNum {public static MyNum MinValue = 0; public static MyNum MaxValue = 0; }'然后在另一个线程中连续写入'MinValue' ...这不会是线程安全的:-) – xanatos

3

这将是我的解决方案;

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); 
     } 
    } 
} 
相关问题