Я не знаю, что именно имел в виду автор этой статьи (может быть, мы должны спросить его / ее), но я думаю, что для этого нужно чуть больше, чем одна строка кода. Дело в том, что динамическое ключевое слово (новое в 4.0 .NET) позволяет так называемый утиный ввод.
Автору статьи пришлось написать 2 класса-оболочки, чтобы FrameworkElement
и FrameworkContentElement
реализовали интерфейс IFrameworkElement
.
Теперь с помощью dynamic
ключей мы можем написать только класс (для поддержания удобства нашего интерфейса).
public interface IFrameworkElement
{
/* Let's suppose we have just one property, since it is a sample */
object DataContext
{
get;
set;
}
}
public class FrameworkElementImpl : IFrameworkElement
{
private readonly dynamic target;
public FrameworkElementImpl(dynamic target)
{
this.target = target;
}
public object DataContext
{
get
{
return target.DataContext;
}
set
{
target.DataContext = value;
}
}
}
public static class DependencyObjectExtension
{
public static IFrameworkElement AsIFrameworkElement(this DependencyObject dp)
{
if (dp is FrameworkElement || dp is FrameworkContentElement)
{
return new FrameworkElementImpl(dp);
}
return null;
}
}
Итак, теперь мы можем написать в нашем коде что-то вроде:
System.Windows.Controls.Button b = new System.Windows.Controls.Button();
IFrameworkElement ife = b.AsIFrameworkElement();
ife.DataContext = "it works!";
Debug.Assert(b.DataContext == ife.DataContext);
Теперь, если вы не хотите писать свой класс-оболочку (или прокси, как хотите) (например, FrameworkElementImpl
в нашем примере), есть несколько библиотек, которые сделают это за вас (импровизированный-интерфейс или Castle DynamicProxy).
Вы можете найти здесь очень простой пример, который использует Castle DynamicProxy:
public class Duck
{
public void Quack()
{
Console.WriteLine("Quack Quack!");
}
public void Swim()
{
Console.WriteLine("Swimming...");
}
}
public interface IQuack
{
void Quack();
}
public interface ISwimmer
{
void Swim();
}
public static class DuckTypingExtensions
{
private static readonly ProxyGenerator generator = new ProxyGenerator();
public static T As<T>(this object o)
{
return generator.CreateInterfaceProxyWithoutTarget<T>(new DuckTypingInterceptor(o));
}
}
public class DuckTypingInterceptor : IInterceptor
{
private readonly object target;
public DuckTypingInterceptor(object target)
{
this.target = target;
}
public void Intercept(IInvocation invocation)
{
var methods = target.GetType().GetMethods()
.Where(m => m.Name == invocation.Method.Name)
.Where(m => m.GetParameters().Length == invocation.Arguments.Length)
.ToList();
if (methods.Count > 1)
throw new ApplicationException(string.Format("Ambiguous method match for '{0}'", invocation.Method.Name));
if (methods.Count == 0)
throw new ApplicationException(string.Format("No method '{0}' found", invocation.Method.Name));
var method = methods[0];
if (invocation.GenericArguments != null && invocation.GenericArguments.Length > 0)
method = method.MakeGenericMethod(invocation.GenericArguments);
invocation.ReturnValue = method.Invoke(target, invocation.Arguments);
}
}
Как видите, в этом случае с помощью нескольких строк кода можно получить тот же результат, что автор получил с помощью
около 624 строк [...] для каждого элемента
person
Il Vic
schedule
14.08.2016