Linq.Expressions值类型隐式转换

时间:2014-09-30 14:30:59

标签: c# linq-expressions

我怎样排序" up-cast"如果我有一个表达式Expression.Constant(3)Expression.Constant(3d),它会将int上转换为double?

我知道我可以使用Expression.Convert()转换,但是确定哪种类型可以隐式上传的最佳方法是什么?

我正在编写一个简单的等式计算器,因此唯一预期的输入类型是值类型

2 个答案:

答案 0 :(得分:1)

这里要考虑的关键是LINQ和动态语言运行时使用的System.Linq.Expressions被设计为与语言无关的代码模型。我们的想法是创建一个"编译器"可以将任意语言的表达式转换为LINQ / DLR树。不同的语言有自己的规则来管理隐式或显式发生的转换类型,因此表达式树API和编译器在要求类型完全匹配时往往非常严格。这是"编译器编写器"的工作。 (或者生成这些表达式树的任何代码)以显式注入与源语言语义匹配所需的任何转换。

您的自定义表达式语言的语义由您决定;你可以选择以C#之类的现有语言为基础,但你不会在LINQ / DLR框架中找到很多设施来告诉你哪种类型的转换"应该"隐式发生,因为没有标准的规则集;这些规则与语言有关。无论您决定采用哪种规则,最终都需要将必要的转换注入表达式树。这是一项非常重要的任务,并且没有任何一种尺寸适合所有"可以简单地发布到StackOverflow的解决方案。

从好的方面来说,没有必要花费很少的成本。树中的Convert个表达式;如果从一种类型到另一种类型的字节码级转换实际上是无操作,则在编译表达式时不会发出额外的字节码。

答案 1 :(得分:0)

浏览Reflector中的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;
    }