我该如何排序“上传”,如果我有一个表达式Expression.Constant(3)
和Expression.Constant(3d)
,它会将int上变换为double?Linq.Expressions值类型隐式铸造
我知道我可以使用Expression.Convert()
进行转换,但确定哪种类型可以隐式上传的最佳方法是什么?
我正在写一个简单的等式评估,所以只能期望的输入类型是值类型
我该如何排序“上传”,如果我有一个表达式Expression.Constant(3)
和Expression.Constant(3d)
,它会将int上变换为double?Linq.Expressions值类型隐式铸造
我知道我可以使用Expression.Convert()
进行转换,但确定哪种类型可以隐式上传的最佳方法是什么?
我正在写一个简单的等式评估,所以只能期望的输入类型是值类型
这里要考虑的关键问题是,System.Linq.Expressions
,其被两个LINQ和动态语言运行时,被设计成一个语言无关代码模型。这个想法是为了创建一个可以将任意语言的表达式转换成LINQ/DLR树的“编译器”。不同的语言有自己的规则来管理隐式或显式的转换类型,因此表达式树API和编译器对于要求类型精确匹配的要求非常严格。 “编译器编写器”(或任何代码生成这些表达式树)的工作是显式注入需要匹配源语言语义的任何转换。
您的自定义表达式语言的语义取决于您;您可以选择将它们从现有语言(例如C#)中提取出来,但是您不会在LINQ/DLR框架中找到许多工具来告诉您“应该”隐式发生哪种类型的转换,因为没有标准的规则集这个;这样的规则是语言相关的。无论您决定什么规则,它最终都取决于您将必要的转换注入到表达式树中。这是一项不平凡的任务,并且没有“一刀切”的解决方案,只需发布到StackOverflow即可。
好的方面是,在你的树中使用“不必要的”Convert
表达式的代价很小;如果从一种类型到另一种类型的字节码级别转换实际上是空操作,那么编译表达式时不会发出额外的字节码。
在浏览时通过反射的System.Linq.Expressions命名空间,我发现下面的方法我用了一个动态的,而不是办法。
public static bool IsImplicitNumericConversion(Type source, Type destination)
{
TypeCode typeCode = Type.GetTypeCode(source);
TypeCode code2 = Type.GetTypeCode(destination);
switch (typeCode)
{
case TypeCode.Char:
switch (code2)
{
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.SByte:
switch (code2)
{
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
break;
case TypeCode.Byte:
switch (code2)
{
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.Int16:
switch (code2)
{
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.UInt16:
switch (code2)
{
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.Int32:
switch (code2)
{
case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.UInt32:
switch (code2)
{
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.Int64:
case TypeCode.UInt64:
switch (code2)
{
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
case TypeCode.Single:
return (code2 == TypeCode.Double);
default:
return false;
}
return false;
}
您引用的方法在内部用于特定目的,并且您不应该认为您可以放弃显式的'Convert',因为此方法告诉您两种类型可以隐式转换。它最终取决于操作数的使用位置和方式。 – 2014-10-08 16:01:26
我不希望那里有任何获得给定'Type'在运行时可以隐式转换为的所有类型的列表的方式。您应该重新设计程序以避免出现这种情况,并且不要在运行时尝试这样做。 – Servy 2014-09-30 14:37:04
你刚刚描述了一个编译器的工作,它知道这些基于C#语言规范的东西。 – fejesjoco 2014-09-30 14:56:54
没有任何类型。只是价值类型 – 2014-09-30 15:29:03