当要求Expression <Func <T,decimal >>时,防止隐式转换为int

时间:2019-09-09 22:19:44

标签: c#

因此,int可隐式转换为decimal。当需要Expression属性的decimal时,会导致问题,而传递带有隐式强制类型转换的Expression属性的int。由于隐式强制转换,因此不会给出编译器错误。

例如:

class Thing {
   public int IntProperty { get; set; }
}

void DoSomething(
   Expression<Func<Thing, decimal>> pDecimalExpression
) {
   ...
}

DoSomething(t => t.IntProperty); // compiles; IntProperty is implicitly cast to decimal

在编译时是否可以确保我确实获得了decimal属性?如果我这样传递带有隐式强制转换的表达式,则会出现编译器错误。

(由于我正在使用反射,所以最终出现运行时错误,提示我正在使用的属性无法赋予decimal值。我觉得我能做的最好的就是检测在运行时输入自己的类型不匹配,而只会抛出稍微好一点的错误。)

2 个答案:

答案 0 :(得分:5)

我会使用通用约束。由于无法直接使用结构类型,因此您仍然可以使用IEquatable<T>来限制可以作为T传递的内容(内置类型实现此接口)。缺点是,任何实现IEquatable<decimal>的东西都将被允许作为T通用参数(在您的情况下可能会出现问题)。

void DoSomething<T>(Expression<Func<Thing, T>> pDecimalExpression)
    where T : struct, IEquatable<decimal> {
    ...
}

第二个选项是编写自定义的Roslyn Analyzer,以在编译时验证代码。

希望有帮助。

答案 1 :(得分:3)

您可以使用一个技巧。编译器将更喜欢使用int进行重载,因此请为其提供重载并使用ObsoleteAttribute's来发出编译时错误。

像这样声明DoSomething

void DoSomething(Expression<Func<Thing, decimal>> pDecimalExpression)
{
    // …
}

[Obsolete("No, no, no!", true)] // the true here causes an error instead of a warning
void DoSomething(Expression<Func<Thing, int>> pIntExpression)
{
    // just in case someone would call this method via reflection
    throw new NotSupportedException();
}

和以下调用会导致编译时错误:

DoSomething(t => t.IntProperty);