Duck type testing with C# 4 for dynamic objects

前端 未结 5 484
遇见更好的自我
遇见更好的自我 2020-12-02 22:57

I\'m wanting to have a simple duck typing example in C# using dynamic objects. It would seem to me, that a dynamic object should have HasValue/HasProperty/HasMethod methods

5条回答
  •  情歌与酒
    2020-12-02 23:41

    Implementation of the HasProperty method for every IDynamicMetaObjectProvider WITHOUT throwing RuntimeBinderException.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Dynamic;
    using Microsoft.CSharp.RuntimeBinder;
    using System.Linq.Expressions;
    using System.Runtime.CompilerServices;
    
    
    namespace DynamicCheckPropertyExistence
    {
        class Program
        {        
            static void Main(string[] args)
            {
                dynamic testDynamicObject = new ExpandoObject();
                testDynamicObject.Name = "Testovaci vlastnost";
    
                Console.WriteLine(HasProperty(testDynamicObject, "Name"));
                Console.WriteLine(HasProperty(testDynamicObject, "Id"));            
                Console.ReadLine();
            }
    
            private static bool HasProperty(IDynamicMetaObjectProvider dynamicProvider, string name)
            {
    
    
    
                var defaultBinder = Binder.GetMember(CSharpBinderFlags.None, name, typeof(Program),
                                 new[]
                                         {
                                             CSharpArgumentInfo.Create(
                                             CSharpArgumentInfoFlags.None, null)
                                         }) as GetMemberBinder;
    
    
                var callSite = CallSite>.Create(new NoThrowGetBinderMember(name, false, defaultBinder));
    
    
                var result = callSite.Target(callSite, dynamicProvider);
    
                if (Object.ReferenceEquals(result, NoThrowExpressionVisitor.DUMMY_RESULT))
                {
                    return false;
                }
    
                return true;
    
            }
    
    
    
        }
    
        class NoThrowGetBinderMember : GetMemberBinder
        {
            private GetMemberBinder m_innerBinder;        
    
            public NoThrowGetBinderMember(string name, bool ignoreCase, GetMemberBinder innerBinder) : base(name, ignoreCase)
            {
                m_innerBinder = innerBinder;            
            }
    
            public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
            {
    
    
                var retMetaObject = m_innerBinder.Bind(target, new DynamicMetaObject[] {});            
    
                var noThrowVisitor = new NoThrowExpressionVisitor();
                var resultExpression = noThrowVisitor.Visit(retMetaObject.Expression);
    
                var finalMetaObject = new DynamicMetaObject(resultExpression, retMetaObject.Restrictions);
                return finalMetaObject;
    
            }
    
        }
    
        class NoThrowExpressionVisitor : ExpressionVisitor
        {        
            public static readonly object DUMMY_RESULT = new DummyBindingResult();
    
            public NoThrowExpressionVisitor()
            {
    
            }
    
            protected override Expression VisitConditional(ConditionalExpression node)
            {
    
                if (node.IfFalse.NodeType != ExpressionType.Throw)
                {
                    return base.VisitConditional(node);
                }
    
                Expression> dummyFalseResult = () => DUMMY_RESULT;
                var invokeDummyFalseResult = Expression.Invoke(dummyFalseResult, null);                                    
                return Expression.Condition(node.Test, node.IfTrue, invokeDummyFalseResult);
            }
    
            private class DummyBindingResult {}       
        }
    }
    

提交回复
热议问题