我尝试简而言之:FrameworkElement和FrameworkContentElement共享许多相同的API,但没有通用的接口。仅DependencyObject作为基类。

我遇到了this implementation of IFrameworkElement,它会手动添加一个接口和两个包装器类。现在,此代码在.NET 3.5中实现,作者指出,在.NET 4中进行动态编程会容易得多:


  实际的代码非常简单,但是每个元素大约需要624行。 (这将是一种以动态语言实现的简单得多的一行实现-C#4.0即将推出:))。


我会很好奇该实现的样子。我认为它将归结为IFrameworkElement的动态实现,并阅读有关ExpandoObjectDynamicObject的信息,以查看是否可以实现自己,但我有些困惑。我猜一个人可以编写一个DynamicObject的自定义实现-但这不是一个衬里。动态编程真的可以使它变得如此容易吗?我什至不需要成为一个班轮,我会用10甚至100行代替原来的1250。

我在想这样的事情:

// Example, not working:
public IFrameworkElement AsFrameworkElement(FrameworkElement ele)
{
  dynamic ife = ele as IFrameworkElement;
  return ife;
}

IFrameworkElement frameworkElement = AsFrameworkElement(new Button());
frameworkElement.DataContext = "Whatever";

IFrameworkElement frameworkContentElement = AsFrameworkElement(new Paragraph());
frameworkContentElement.DataContext = "Whatever again";

最佳答案

我不知道那篇文章的作者究竟是什么意思(也许我们应该问问他/她),但是我想它需要的不仅仅是一行代码。
关键是dynamic keyword(4.0 .NET的新功能)允许使用所谓的duck typing

本文的作者必须编写2个包装器类,以使FrameworkElementFrameworkContentElement实现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),则可以使用一些库(impromptu-interfaceCastle DynamicProxy)。

您可以找到here一个使用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行[...]

关于c# - 具有动态编程的FrameworkElement和FrameworkContentElement的通用接口(interface),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38790610/

10-11 06:34