C# 隐式强制转换动态到日期时间?和op_平等

C# 隐式强制转换动态到日期时间?和op_平等,c#,datetime,dynamic,casting,C#,Datetime,Dynamic,Casting,我有自己的动态对象,必须与基本类型相比较。我为要比较的所有类型定义了隐式强制转换运算符。对于大多数基本类型,如int、short、bool、decimal,实现该类型的可为null的强制转换就足以成功比较,但对于DateTime则不行。我是否遗漏了DateTime和decimal之间的一些显著差异,或者是动态实现中的错误 class MyDynamic : DynamicObject { public static implicit operator decimal?(MyDynamic

我有自己的动态对象,必须与基本类型相比较。我为要比较的所有类型定义了隐式强制转换运算符。对于大多数基本类型,如int、short、bool、decimal,实现该类型的可为null的强制转换就足以成功比较,但对于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)
System.InvalidOperationException运算符“Equal”的操作数与方法“op_Equality”的参数不匹配。
位于System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType、Expression left、Expression right、MethodInfo方法、Boolean liftToNull)
at System.Linq.Expressions.Expression.Equal(表达式左、表达式右、布尔liftToNull、MethodInfo方法)
在Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateUserDefinedBinaryOperator(EXPRCALL pExpr)中
在Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL-pExpr)中
位于Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR-pExpr)
位于Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR-pExpr)
在Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr)上
在Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL-pExpr)中
位于Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR-pExpr)
位于Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR-pExpr)
在Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager TypeManager、EXPR pExpr、IEnumerable`1参数列表)
在Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateExpressionTreeFromResult(IEnumerable`1参数,ArgumentObject[]参数,Scope pScope,EXPR pResult)
位于Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder有效负载,IEnumerable`1参数,DynamicMetaObject[]参数,参考DynamicMetaObject deferredBinding)
位于Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder有效负载,IEnumerable`1参数,DynamicMetaObject[]参数,参考DynamicMetaObject deferredBinding)
位于Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder操作,RuntimeBinder binder,IEnumerable`1参数,IEnumerable`1参数,DynamicMetaObject onBindingError)
在Microsoft.CSharp.RuntimeBinder.CSharpBinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject目标、DynamicMetaObject参数、DynamicMetaObject错误建议)
位于System.Dynamic.BinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject目标,DynamicMetaObject参数)
位于System.Dynamic.DynamicMetaObject.BindBaryOperation(BinaryOperationBinder,DynamicMetaObject参数)
位于System.Dynamic.BinaryOperationBinder.Bind(DynamicMetaObject目标,DynamicMetaObject[]参数)
位于System.Dynamic.DynamicMetaObjectBinder.Bind(对象[]参数,ReadOnlyCollection`1参数,LabelTarget returnLabel)
位于System.Runtime.CompilerServices.CallSiteBinder.BindCore(CallSite`1站点,对象[]args)
位于System.Dynamic.UpdateLegates.UpdateAndExecute2(调用站点,T0 arg0,T1 arg1)

在大多数情况下,我的自定义动态应该几乎为null,因此转换为值类型是不需要的。

定义运算符==使代码更简单

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)大小写


不幸的是,规范中没有明确说明动态绑定工作的具体细节。但它适用于
十进制
,而不适用于
日期时间
,这一事实很奇怪。如果您不使用
动态
,例如,如果您对所有这些变量使用
var
,它是否有效?如果“我的”和“日期”变量都不是动态的(不涉及呼叫站点),那么它会按预期工作。在这种情况下,我觉得这是动态处理中的一个错误。我尽量使这些事情尽可能简单(和罕见):(我已经尝试过了,这里您有不明确的错误。您的代码和我的示例:附加信息:调用在以下方法或属性之间不明确:'System.DateTime.operator==(System.DateTime,System.DateTime)'和'ConsoleApplication11.MyDynamic.operator'==(object,ConsoleApplication11.MyDynamic)“您可能忘记了删除“public static implicit operator DateTime?(MyDynamic x)”。是的,如果我们比较dynamics,模糊错误消失了,但是如果我们比较null,则会出现:Assert.True(null!=my);无论如何,感谢您的回答,这在某些情况下是有价值的解决方法。
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);
}