以编程方式获取转换和输出运算符类型

Programmatically get cast and output Types of operator

在 C# 中,给定两个输入 Type,是否可以确定运算符的输出 Type 和隐式向上转换 Type?例如,考虑表达式 s + i。假设我有以下信息:

short s;
int i;
Type leftType = typeof(short);
Type rightType = typeof(int);

我可以确定表达式 s + i 的以下信息吗?

Type leftUpcastType = typeof(int);
Type rightUpcastType = typeof(int);
Type outputType = typeof(int);

我显然可以通过对所有类型和运算符进行大量查找 table 来做到这一点,但可能有更简单的方法。理想情况下,这也适用于具有运算符重载的用户定义 类,但这是次要要求。

是的,您可以使用 dynamic 类型来实现。不过请记住,对于任何无法在 runtime 求和的内容,dynamic 都会抛出异常,因此您需要确保只传递有效值或包装在 try/catch.

var leftType = left.GetType();
var rightType = right.GetType();
var outputType = ((dynamic)left + (dynamic)right).GetType();

然后您可以根据此信息推断是否有一个、两个或两个对象都没有为操作转换。

执行此操作的最佳方法是检查表达式的 return 类型,该表达式将两个您感兴趣的类型的值相加。这样您就不必担心提供有效的 values 用于在运行时添加,当您只关心 return type.

您可以采用现有的表达式并沿着表达式树向下移动(如果有的话),或者执行如下操作:

static Type GetTypeOfSummation<T1, T2>()
{
    var p1 = Expression.Parameter(typeof(T1), "t1");
    var p2 = Expression.Parameter(typeof(T2), "t2");

    LambdaExpression x = DynamicExpression.ParseLambda(new[] { p1, p2 }, null, "t1 + t2");
    return x.Body.Type;
}

static void Main()
{
    Console.WriteLine(GetTypeOfSummation<int, double>());   // System.Double
    Console.WriteLine(GetTypeOfSummation<int, decimal>());  // System.Decimal
    Console.WriteLine(GetTypeOfSummation<float, double>()); // System.Double
}

此泛型方法将 return 加法运算的类型,而不实际执行加法。

您当然也可以使用 Type 实例而不是泛型类型参数来执行此操作,如果这是您想要的:

static Type GetTypeOfSummation(Type t1, Type t2)
{
    var p1 = Expression.Parameter(t1, "t1");
    var p2 = Expression.Parameter(t2, "t2");

    LambdaExpression x = DynamicExpression.ParseLambda(new[] { p1, p2 }, null, "t1 + t2");
    return x.Body.Type;
}

需要说明的是,DynamicExpression来自System.Linq.Dynamic命名空间,可以参考:https://www.nuget.org/packages/System.Linq.Dynamic/