隐式转换动态到DateTime?和op_Equality

时间:2015-01-14 13:11:36

标签: c# datetime dynamic casting

我有自己的动态对象,必须与原始类型相媲美。我为我要比较的所有类型定义了隐式转换运算符。对于大多数原始类型,如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,因此不需要转换为值类型。

1 个答案:

答案 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);
}