C#:找出代码中算术运算的结果类型(例如 int + double = double) [英] C#: Find out result type of arithmetic operations in code (e.g. int + double = double)

查看:44
本文介绍了C#:找出代码中算术运算的结果类型(例如 int + double = double)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图想出一个函数来确定算术运算的结果类型,比如加法:

I'm trying to come up with a function to determine the result type of arithmetic operations, say for the case of addition:

Type TypeOfAddition(Type leftType, Type rightType)
{
  // ???
}

Type TypeOfMultiplication(Type leftType, Type rightType)
{
  // ???
}

// ... same for subtraction and division

这些函数的这些期望结果大概是清楚的;本质上,我的目标与 Visual Studio 在进行算术运算时将类型推断为var"类型变量时所做的相同(在运行时).

These desired result of these functions is probably clear; Essentially, my goal is do to the same (at runtime) that Visual Studio does when inferring types to "var"-type variables when doing arithmetic operations.

例如

public class MyClass
{
    public static string operator +(MyClass left, double right)
    {
        // ...
    }
}

TypeOfAddition(typeof(int), typeof(double)); // Should return typeof(double)
TypeOfAddition(typeof(string), typeof(int)); // Should return typeof(string)
TypeOfAddition(typeof(MyClass), typeof(double));  // Should return typeof(string)

我的基本想法是概念上的实现

My base idea was an implementation like, conceptually

Type TypeOfAddition(Type leftType, Type rightType)
{
  return leftType.GetMethods().Single(x =>
    x.Name == "op_Addition" &&
    x.GetParamters().Count == 2 &&
    x.GetParameters().Last().ParameterType == rightType);
}

但是

A) 这不适用于 int、double 等基本类型,它们似乎没有明确定义运算符重载,并且

A) This won't work for base types like int, double etc., which don't seem to explicitly define operator overloads, and

B) 上面的 linq 子句还不能捕获所有情况(例如继承)

B) The above linq clause won't catch all cases yet (e.g. inheritance)

我可以对基本类型进行硬编码,并尝试为 B) 提出一个聪明的解决方案,但这似乎相对......不优雅.

I could hard-code the base types and try to come up with a smart solution for B) as well, but that seems relatively .. unelegant.

有没有更聪明/更容易/更好的解决方案来解决这个问题?请注意,我只想获得这种运算结果的理论类型,而没有实际明确地执行算术运算.

Is there any smarter / easier / good solution to solving this? Mind you, I only want to get the theoretical type of the result of such an operation, without actually executing an arithmetic operation explicitly.

谢谢!

推荐答案

它当然不漂亮,速度也不快,但它似乎适用于我已经通过的基本测试.

It certainly isn't pretty, and definitely isn't fast, but it appears to work with the basic tests I've ran it through.

请注意,您需要引用 Microsoft.CSharp.dll.

Note that you'll need to have Microsoft.CSharp.dll referenced.

Type TypeOfAddition<TLeft, TRight>()
{
    object GetDefault<T>()
    {
        if (typeof(T).IsValueType)
        {
            return default(T);
        }

        if (typeof(T) == typeof(string))
        {
            return string.Empty;
        }

        return (T)FormatterServices.GetUninitializedObject(typeof(T));
    }

    var binder = Microsoft.CSharp.RuntimeBinder.Binder.BinaryOperation(
        CSharpBinderFlags.None,
        ExpressionType.Add,
        null,
        new CSharpArgumentInfo[] {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        }
    );

    var left = Expression.Parameter(typeof(TLeft));
    var right = Expression.Parameter(typeof(TRight));

    var func = Expression.Lambda(
        Expression.Dynamic(binder, typeof(object), left, right),
        new[] { left, right }
    ).Compile();

    return func
        .DynamicInvoke(GetDefault<TLeft>(), GetDefault<TRight>())
        ?.GetType() ?? typeof(object);
}

示例输出:

public class MyClass
{
    public static string operator +(MyClass left, double right)
    {
        return "";
    }
}

TypeOfAddition<string, int>().Dump();     // System.String
TypeOfAddition<int, double>().Dump();     // System.Double
TypeOfAddition<float, double>().Dump();   // System.Double
TypeOfAddition<MyClass, double>().Dump(); // System.String

这使用 Jeroen 在评论中提到的 (RuntimeBinder) 来创建附加绑定器.然后构建一个动态表达式树来添加TLeftTRight 的默认值.我不得不添加一个名为 GetDefault 的小函数来将 string 解析为一个空字符串,因为我假设你想在尝试时看到 string添加 "" + 0 而不是 null.如果您确实想要查看空值,只需将 GetDefault 调用替换为 default(TLeft)default(TRight)>.

This uses what Jeroen mentioned in the comments (RuntimeBinder) to create a addition binder. It then builds a dynamic expression tree to add the default values of both TLeft and TRight. I had to add a small function called GetDefault to resolve string to an empty string, since I'm assuming you want to see string when trying to add "" + 0 instead of null. If you do want to see nulls, just replace the GetDefault calls with default(TLeft) and default(TRight).

它不调用构造函数(由于使用 GetUninitializedObject) 包含字符串的特殊情况.

It doesn't call constructors (due to using GetUninitializedObject) contains a special case for strings.

可能有很多可能的改进,我全神贯注.

There are likely many possible improvements, and I am all ears.

这篇关于C#:找出代码中算术运算的结果类型(例如 int + double = double)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆