Duck Typing in C#

"when I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck" -- James Whitcomb Riley

 

It's really easy to implement duck typing in C# 4.0 since it introduced dynamic into its toolsets. The following is just some scratch to help me familiar with the dynamic feature (plus dynamic proxy from castle project )

 

 

ExpandedBlockStart.gif 代码
using  System.Collections.Generic;
using  System.Dynamic;
using  System.Linq;

namespace  DynamicDuckTypeing
{
    
class  DynamicWrapper : DynamicObject
    {
        
object  _obj;
        Dictionary
< string object >  _dictionary  =   new  Dictionary < string object > ();

        
public  DynamicWrapper( object  obj)
        {
            _obj 
=  obj;
        }

        
public   override   bool  TrySetMember(SetMemberBinder binder,  object  value)
        {
            
return  TrySetMember(binder.Name, value);
        }

        
internal   virtual   bool  TrySetMember( string  name,  object  value)
        {
            var memberInfo 
=  _obj.GetType().GetMember(name);
            
if  (memberInfo.Count()  ==   0 )
            {
                _dictionary[name] 
=  value;
            }
            
else
            {
                _obj.GetType().InvokeMember(name,
                    System.Reflection.BindingFlags.SetProperty,
                    
null ,
                    _obj,
                    
new   object [] { value });
            }
            
return   true ;
        }

        
internal   virtual   bool  TryGetMember( string  name,  out   object  result)
        {
            var memberInfo 
=  _obj.GetType().GetMember(name);
            
if  (memberInfo.Count()  ==   0 )
            {
                
return  _dictionary.TryGetValue(name,  out  result);
            }
            
else
            {

                
bool  invokeSucceed  =   true ;
                
try
                {
                    result 
=  _obj.GetType().InvokeMember(name,
                        System.Reflection.BindingFlags.GetProperty,
                        
null ,
                        _obj,
                        
null );
                }
                
catch
                {
                    result 
=   null ;
                    invokeSucceed 
=   false ;
                }
                
return  invokeSucceed;
            }
        }
        
public   override   bool  TryGetMember(GetMemberBinder binder,  out   object  result)
        {
            
return  TryGetMember(binder.Name, out  result);
            
        }

        
public   override   bool  TryInvokeMember(InvokeMemberBinder binder,  object [] args,  out   object  result)
        {
            
return  TryInvokeMember(binder.Name, args,  out  result);
        }

        
internal   bool  TryInvokeMember( string  memberName,  object [] args,  out   object  result)
        {
            _obj.GetType().InvokeMember(memberName,
              System.Reflection.BindingFlags.InvokeMethod,
              
null ,
              _obj, args);
            result 
=   null ;
            
return   true ;
        }

        
public   override   bool  TryConvert (ConvertBinder binder,  out   object  result)
        {          
            result 
=  Generator.GenerateProxy(binder.Type, this );
            
return   true ;
        }
    }
}

 

 

 

ExpandedBlockStart.gif 代码
using  System;
using  Castle.DynamicProxy;
using  Castle.Core.Interceptor;


namespace  DynamicDuckTypeing
{
    
class  Generator
    {
        
static   readonly  ProxyGenerator _generator  =   new  ProxyGenerator();       

        
internal   static   object  GenerateProxy(Type type, DynamicWrapper dynamicWrapper)
        {
            
return  _generator.CreateInterfaceProxyWithoutTarget(type,  new  Interceptor(dynamicWrapper));
        }
    }

    
class  Interceptor : IInterceptor
    {
        DynamicWrapper _wrapper;
        
public  Interceptor(DynamicWrapper wrapper)
        {
            _wrapper 
=  wrapper;
        }
        
public   void  Intercept(IInvocation invocation)
        {
            
            
object  result;

            
// property access will be converted to get_XXX and set_XXX, use String.Substring(4) to get the real proertyName
             if  (invocation.Method.Name.StartsWith( " get_ " ))
            {
                invocation.ReturnValue 
=  _wrapper.TryGetMember(invocation.Method.Name.Substring( 4 ),  out  result);
                invocation.ReturnValue 
=  result;
            }
            
else   if  (invocation.Method.Name.StartsWith( " set_ " ))
            {
                _wrapper.TrySetMember(invocation.Method.Name.Substring(
4 ), invocation.Arguments[ 0 ]);
            }
            
else
            {
                _wrapper.TryInvokeMember(invocation.Method.Name, invocation.Arguments, 
out  result);
                invocation.ReturnValue 
=  result;
            }
        }
    }
}

 

 

 

ExpandedBlockStart.gif 代码
using  System;

namespace  DynamicDuckTypeing
{
    
public   interface  IQuack
    {
        
void  Quack();   
    }

    
class  Duck
    {        
        
public   void  Quack()
        {
            Console.WriteLine(
" Duck Quack " );
        }
    }

    
class  Goose
    {
        
public   void  Quack()
        {
            Console.WriteLine(
" Goose goose " );
        }
    }
    
class  Program
    {
        
static   void  Main( string [] args)
        { 
            dynamic dynamicDuck 
=   new  DynamicWrapper(  new  Duck());            
            dynamicDuck.Name 
=   " mallard duck " ;           
            dynamicDuck.Age 
=   2 ;
            Console.WriteLine(
" Name: {0}, Age: {1} " ,dynamicDuck.Name, dynamicDuck.Age);
            dynamicDuck.Quack();
            Console.WriteLine();
                        
            IQuack q 
=  dynamicDuck;            
            q.Quack();

            dynamic dynamicGoose 
=   new  DynamicWrapper( new  Goose());
            q 
=  dynamicGoose;
            q.Quack();

            q 
=  (dynamic) new  DynamicWrapper( new   object ());
            
try
            {
                q.Quack();
                Console.WriteLine(
" can't be there " );
            }
            
catch  (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }
    }
}

 

 

 

                                                       

转载于:https://www.cnblogs.com/hiber/archive/2010/01/05/1639769.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值