Нет желания загружать еще один экземпляр Visual Studio или скачивать проект, а взглянуть на исходный код интересно? Тогда вот он:
Исходный код Dynamic Decorator
// DynamicDecorator
// <copyright file="DynamicDecorator.cs">
// Copyright (c) Andrey Veselov. All rights reserved.
// License: Apache License 2.0
// </copyright>
// <author>Andrey Veselov</author>
// Contact: http://andrey.moveax.ru/contact.aspx
namespace Patterns.Decorator
{
using System;
using System.Dynamic;
using System.Reflection;
using Castle.DynamicProxy;
/// <summary>Dynamic implementation of the Decorator pattern.</summary>
/// <typeparam name="TComponentInterface">The interface of the component.</typeparam>
public class DynamicDecorator<TComponentInterface> : DynamicObject, IInterceptor
{
/// <summary>Component - defines an object to which
/// additional responsibilities can be attached.</summary>
protected TComponentInterface _component;
/// <summary>Represents component type.</summary>
private Type _componentType;
/// <summary>Initializes a new instance of the
/// <see cref="DynamicDecorator<TComponentInterface>"/> class.</summary>
/// <param name="component">The component to which additional
/// responsibilities can be attached.</param>
public DynamicDecorator(TComponentInterface component)
{
this.Component = component;
var _generator = new ProxyGenerator();
this.Interface = (TComponentInterface)_generator.CreateInterfaceProxyWithoutTarget(
typeof(TComponentInterface), this);
}
/// <summary>Gets or sets the object to which additional
/// responsibilities can be attached.</summary>
public TComponentInterface Component
{
get { return this._component; }
set
{
this._component = value;
this._componentType = this._component.GetType();
}
}
/// <summary>Gets the component interface.</summary>
/// <value>The dynamic proxy used to implement the TComponent interface.</value>
public TComponentInterface Interface { get; private set; }
#region DynamicObject overrides
/// <summary>Provides the implementation for operations that set member values.</summary>
/// <param name="binder">Provides information about the object
/// that called the dynamic operation.</param>
/// <param name="value">The value to set to the member.</param>
/// <returns>true if the operation is successful; otherwise, false.</returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// search for a property
PropertyInfo property = this._componentType.GetProperty(
binder.Name, BindingFlags.Public | BindingFlags.Instance);
if (property != null) {
property.SetValue(this._component, value, null);
return true;
}
// search for a public field
FieldInfo field = this._componentType.GetField(
binder.Name, BindingFlags.Public | BindingFlags.Instance);
if (field != null) {
field.SetValue(this._component, value);
return true;
}
return base.TrySetMember(binder, value);
}
/// <summary>Provides the implementation for operations that get member values.</summary>
/// <param name="binder">Provides information about the object
/// that called the dynamic operation.</param>
/// <param name="result">The result of the get operation.</param>
/// <returns>true if the operation is successful; otherwise, false.</returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// search for a property
PropertyInfo property = this._componentType.GetProperty(
binder.Name, BindingFlags.Public | BindingFlags.Instance);
if (property != null) {
result = property.GetValue(this._component, null);
return true;
}
// search for a public field
FieldInfo field = this._componentType.GetField(
binder.Name, BindingFlags.Public | BindingFlags.Instance);
if (field != null) {
result = field.GetValue(this._component);
return true;
}
return base.TryGetMember(binder, out result);
}
/// <summary>Provides the implementation for operations that invoke a member.</summary>
/// <param name="binder">Provides information about the dynamic operation.</param>
/// <param name="args">The arguments that are passed to the object member
/// during the invoke operation.</param>
/// <param name="result">The result of the member invocation.</param>
/// <returns>true if the operation is successful; otherwise, false.</returns>
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args,
out object result)
{
MethodInfo method = this._componentType.GetMethod(
binder.Name, BindingFlags.Public | BindingFlags.Instance,
null, this.GetArgumentsTypes(args), null);
if (method != null) {
result = method.Invoke(this._component, args);
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
#endregion
#region Castle IInterceptor
/// <summary>Intercepts the specified invocation.</summary>
/// <param name="invocation">The invocation.</param>
public void Intercept(IInvocation invocation)
{
Type decoratorType = this.GetType();
Type[] argTypes = this.GetArgumentsTypes(invocation.Arguments);
MethodInfo method = decoratorType.GetMethod(
invocation.Method.Name, BindingFlags.Public | BindingFlags.Instance,
null, argTypes, null);
if (method != null) {
invocation.ReturnValue = method.Invoke(this, invocation.Arguments);
return;
}
method = this._componentType.GetMethod(
invocation.Method.Name, BindingFlags.Public | BindingFlags.Instance,
null, argTypes, null);
if (method != null) {
invocation.ReturnValue = method.Invoke(this._component, invocation.Arguments);
return;
}
// No match was found for required method
string argList = this.GetArgumentsString(invocation.Arguments);
throw new InvalidOperationException(
string.Format("No match was found for method {0}({1}).",
invocation.Method.Name, argList));
}
#endregion
/// <summary>Gets the component.</summary>
/// <returns>The component.</returns>
public TComponentInterface GetComponent()
{
var decorator = this.Component as DynamicDecorator<TComponentInterface>;
if (decorator != null) {
return decorator.GetComponent();
}
return this.Component;
}
/// <summary>Sets the component.</summary>
/// <param name="component">The component to set.</param>
public void SetComponent(TComponentInterface component)
{
var decorator = this.Component as DynamicDecorator<TComponentInterface>;
if (decorator != null) {
decorator.SetComponent(component);
return;
}
this.Component = component;
}
/// <summary>Gets the list of arguments types.</summary>
/// <param name="args">An object array that contains arguments.</param>
/// <returns>The list of arguments types.</returns>
private Type[] GetArgumentsTypes(object[] args)
{
Type[] argTypes = new Type[args.GetLength(0)];
int index = 0;
foreach (var arg in args) {
argTypes[index] = arg.GetType();
index++;
}
return argTypes;
}
/// <summary>Gets the list of arguments types as string.</summary>
/// <param name="args">An object array that contains arguments.</param>
/// <returns>The list of arguments types as string.</returns>
private string GetArgumentsString(object[] args)
{
string argList = string.Empty;
bool isFirstArgument = true;
foreach (var arg in args) {
if (isFirstArgument) {
isFirstArgument = false;
}
else {
argList += ", ";
}
argList += arg.GetType().ToString();
}
return argList;
}
}
/// <summary>Dynamic implementation of the Decorator pattern.</summary>
/// <typeparam name="TComponent">The type of the component.</typeparam>
/// <typeparam name="TComponentInterface">The interface of the component.</typeparam>
public class DynamicDecorator<TComponent, TComponentInterface> :
DynamicDecorator<TComponentInterface>
where TComponent : class, TComponentInterface, new()
{
/// <summary>Initializes a new instance of the
/// <see cref="DynamicDecorator<TComponent, TComponentInterface>"/>
/// class.</summary>
public DynamicDecorator() : base((TComponentInterface)new TComponent()) { }
}
}
Исходный код примера использования
namespace DynamicDecoratorDemo
{
using System;
using Patterns.Decorator;
public interface IElement
{
string Text { get; set; }
void Draw();
}
public class Element : IElement
{
public string Text { get; set; }
public void Draw()
{
Console.WriteLine("Drawing element ({0})", this.Text);
}
}
public class ElementStrikedDecorator : DynamicDecorator<IElement>
{
public ElementStrikedDecorator(IElement component) : base(component) { }
public void Draw()
{
this._component.Draw();
this.Strike();
}
private void Strike()
{
Console.WriteLine("Striked");
}
}
public class ElementBgndDecorator : DynamicDecorator<IElement>
{
public ElementBgndDecorator(IElement component) : base(component) { }
public string BackgroundFileName { get; set; }
public void Draw()
{
this.SetBackground();
this._component.Draw();
}
private void SetBackground()
{
Console.WriteLine("Background: {0}", this.BackgroundFileName);
}
}
public class MyDynamic : System.Dynamic.IDynamicMetaObjectProvider
{
public void DefinedMethod()
{
Console.WriteLine("DefinedMethod");
}
public System.Dynamic.DynamicMetaObject GetMetaObject(
System.Linq.Expressions.Expression parameter)
{
throw new NotImplementedException();
}
}
class Program
{
public static void DrawElement(string title, IElement element)
{
Console.WriteLine("{0} ---------------------------", title);
element.Draw();
Console.WriteLine(string.Empty);
}
static void Main(string[] args)
{
//dynamic myDynamicObject = new MyDynamic();
//myDynamicObject.DefinedMethod();
//myDynamicObject.Test();
Element element = new Element();
DrawElement("Base element", element);
dynamic elementBgnd = new ElementBgndDecorator(element);
elementBgnd.BackgroundFileName = "SomeBgndFile.png";
dynamic elementStriked = new ElementStrikedDecorator(elementBgnd.Interface);
elementStriked.Text = "Demo";
DrawElement("Striked element with background", elementStriked.Interface);
IElement sourceElement = elementStriked.GetComponent();
DrawElement("Element with background", sourceElement);
Console.WriteLine("Press any key ...");
Console.ReadKey();
}
}
}
Не забудьте подключить к проекту сборку Castle Project Core.
Ну и еще раз ссылка на демонстрационный проект для Visual Studio 2010:
DynamicDecorator.zip (141 kb).