因此,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
值。我觉得我能做的最好的就是检测在运行时输入自己的类型不匹配,而只会抛出稍微好一点的错误。)
答案 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);