我有自己的动态对象,必须与原始类型相媲美。我为我要比较的所有类型定义了隐式转换运算符。对于大多数原始类型,如int,short,bool,十进制实现强制转换为此类型的可空版本足以成功进行比较,但不适用于DateTime。我是否错过了DateTime和decimal之间的一些显着差异,还是在动态实现中出错了?
class MyDynamic : DynamicObject
{
public static implicit operator decimal?(MyDynamic nullable)
{
return null;
}
public static implicit operator DateTime?(MyDynamic x)
{
return null;
}
//public static implicit operator DateTime(MyDynamic x)
//{
// return DateTime.MinValue;
//}
}
[Fact]
public void FactMethodName()
{
dynamic my = new MyDynamic();
dynamic date = DateTime.Now;
dynamic dec = 1m;
Assert.False(dec == my);
// throws
Assert.False(date == my);
}
如果未定义隐式强制转换,则错误消息为:
System.InvalidOperationExceptionThe operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
堆栈跟踪是:
System.InvalidOperationExceptionThe operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull)
at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateUserDefinedBinaryOperator(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable`1 listOfParameters)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateExpressionTreeFromResult(IEnumerable`1 parameters, ArgumentObject[] arguments, Scope pScope, EXPR pResult)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, ref DynamicMetaObject deferredBinding)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, ref DynamicMetaObject deferredBinding)
at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
at Microsoft.CSharp.RuntimeBinder.CSharpBinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
at System.Dynamic.BinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg)
at System.Dynamic.DynamicMetaObject.BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
at System.Dynamic.BinaryOperationBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore(CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2<T0,T1,TRet>(CallSite site, T0 arg0, T1 arg1)
在大多数情况下,我的自定义动态应该几乎为null,因此不需要转换为值类型。
答案 0 :(得分:0)
定义operator ==使代码更简单。
public static bool operator ==(MyDynamic lhs, object rhs)
{
if (rhs is MyDynamic)
return lhs.Equals(rhs);
else
return false;
}
public static bool operator !=(MyDynamic lhs, object rhs)
{
if (rhs is MyDynamic)
return !lhs.Equals(rhs);
else
return true;
}
public static bool operator ==(object lhs, MyDynamic rhs)
{
if (lhs is MyDynamic)
return lhs.Equals(rhs);
else
return false;
}
public static bool operator !=(object lhs, MyDynamic rhs)
{
if (lhs is MyDynamic)
return !lhs.Equals(rhs);
else
return true;
}
修改强> 我明确地实现了(MyDynamic == object)和(object == MyDynamic)。因为重写TryBinaryOperation()无法捕获(object == MyDynamic)的情况。
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
{
if (binder.Operation == System.Linq.Expressions.ExpressionType.Equal) { ... }
return base.TryBinaryOperation(binder, arg, out result);
}