C#:找出代码中算术运算的结果类型(例如 int + double = double) [英] C#: Find out result type of arithmetic operations in code (e.g. 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) 来创建附加绑定器.然后构建一个动态表达式树来添加TLeft
和TRight
的默认值.我不得不添加一个名为 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屋!