如何用C#构建一个mix-in架构框架?

发布于 2024-10-05 15:01:39 字数 585 浏览 7 评论 0原文

我有一个想要构建的控件框架的概念。这个想法的不同之处在于,我不打算采取“一刀切”的方法或“一个控制统治所有”的方法。

举个例子,Telerik 制作了一个非常好的网格控件,ComponentOne、Xceed 等也是如此。但是,它们都是巨大的控件,具有成百上千的方法和属性、复杂的对象模型层次结构等……这些经常发生。网格对于你所需要的东西来说太过分了,但是你仍然必须承担学习整个网格来做一些简单事情的艰巨任务。

我的概念更多的是一种“混合”方法。您可以在其中创建一个非常简单的控件,然后构建可以按菜单“添加”到控件的功能。例如,您有一个简单的网格,并且您想要添加每个网格“部分”以及页眉和页脚。

好吧,那么问题出在哪里呢?执行此类操作的传统方法是通过多重继承,而 C# 不支持这种方式。即使它确实支持它,我仍然认为 MI 增加的问题多于它解决的问题。

因此,我正在征求有关如何解决这个问题的意见。 MEF 会是一个潜在的解决方案吗?

编辑:

我想到的是,可以使用表达式树从各种表达式构建控件。我必须再考虑一下,但这是一个有趣的概念。

另一个可能的选项可能是“控制生成器”,它根据所选功能生成组件。这看起来更复杂,但使用 T4 可能是可以管理的。

I have a concept for a framework of controls that I would like to build. What makes this idea different is that I do not intend to take the "one size fits all" approach or the "one control to rule them all" approach.

As an example, Telerik makes a very nice Grid control, as does ComponentOne, Xceed, etc.. However, they are all gigantic controls with hundreds or thousands of methods and properties, complex object model hiearchies, etc... All too often these grids are way overkill for what you need, but you still have to take on the herculean task of learning the entire grid to do something simple.

My concept is more of an "mix-in" aproach. Where you create a very simple control, and then build features that you can "add-in" to the control a la carte. For example, you have a simple grid, and you want to add grid "sections" with headers and footers for each.

Ok, so where's the problem? The traditional way of doing something like this is via multiple inheritance, which C# does not support. Even if it did support it, I'm still of the opinion that MI adds more problems than it solves.

So I'm soliciting SO for opinions on how to approach this problem. Would MEF be a potential solution?

EDIT:

Something that occurs to me is that it could be possible to use expression trees to build the control from various expressions. I'd have to think through this some more, but it's an interesting concept.

Another possible option might be a "Control Generator" that generates an assembly based on a the selected features. That seems more complex, but with T4 might be managable.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

猫弦 2024-10-12 15:01:39

几个选项

  1. 考虑装饰器模式;扩展您可以在运行时构建的相当简约的类的行为的小对象。 Dotnet 框架中的典型示例将围绕 IO 流(例如 StreamReader/Writer、TextStreamReader/Writer、FileStreamReader/Writer);它在 OO UI 框架中也相当常见,典型的示例类似于 var window=new Horizo​​ntalScrollingWindowDecorator(new VerticalScrollingWindowDecorator(new Window));

  2. 状态、策略、命令和复合模式提供各种替代方案来处理行为组合,而不需要大量控制流。例如,您将某些类型的行为委托给对象的当前 State(某些类方法基本上调用当前对象 State 的方法)。您还可以将行为委托给命令对象,或使用复合命令构建复杂的命令。与继承相比,单继承通常会让您更​​喜欢对象的组合,这些都是组合行为的经典模式,可以很好地与单继承配合使用。

  3. 当特定实例需要实现一些小行为时,您可以将委托用于函数式编程中常见的“中间洞”模式。

  4. 您可以使用 PostSharp 或类似的面向方面的编程工具来执行运行时或编译时行为编织,对于多个不同类所需的行为与主要职责没有太大关系的情况特别有用

A few options

  1. Consider the Decorator pattern; small objects that extend behavior of a fairly minimalist class that you can build up at runtime. The canonical example in the Dotnet framework would be around the IO streams (e.g. StreamReader/Writer, TextStreamReader/Writer, FileStreamReader/Writer); it's fairly common also in OO UI frameworks, with the typical example looking something like var window=new HorizontalScrollingWindowDecorator(new VerticalScrollingWindowDecorator(new Window));

  2. The State, Strategy, Command, and Composite patterns offer various alternatives for dealing with composition of behavior without requiring lots of control flow. For example, you delegate certain types of behavior to the current State of your object (some of your class methods basically call methods of the current object State). You can also delegate behavior to command objects, or build up complex commands using composite commands. Single inheritance generally leads you to favor composition of objects over inheritance, and these are all classic patterns for composing behavior that work well with single-inheritance.

  3. You can use delegates for the "hole in the middle" pattern that's commonplace in functional programming, when some small piece of behavior needs to be implemented by a particular instance.

  4. You can use PostSharp or a similar aspect-oriented programming tool to do runtime or compile-time weaving of behavior, especially useful for cases when behavior needed by several different classes that doesn't have much to do with the primary responsibility of that class.

○愚か者の日 2024-10-12 15:01:39

就我个人而言,我认为多重继承无论如何都是实现这种设计的糟糕方法。大多数时候,多重继承似乎是一个糟糕的设计。继承远非组件之间的严格关系。

组合要灵活得多,在这种情况下,MEF 将是一个非常好的起点。

控件的基类将是一个行为容器 - 本质上是一个 MEF 容器。

它还留下了其他类如何与您的控件交互的问题。有很多选择。例如,基本控件上的标准接口、消息传递,甚至在 C# 4.0 中使用动态绑定。

Personally I think multiple inheritance would be a bad way to implement this kind of design anyway. It seems that multiple inheritance is a bad design most of the time. Inheritance is far to rigid a relationship between components.

Composition is far more flexible, in which case MEF would be a very good starting point for this.

The base class for your controls would be a container of behaviours - essentially a MEF container.

It still leaves the question of how other classes interact with your controls. There are many options. For example standard interfaces on the base control, messaging, or even using dynamic binding in C# 4.0.

任谁 2024-10-12 15:01:39

我想尝试回答这个问题,但不评论这是否是一个值得解决的问题。

我还没有尝试过这个组件,但理论上有 装饰器模式:你可以添加插件在运行时拦截控件的(键盘和鼠标)输入和(屏幕)输出。

I'd like to try to answer without commenting on whether it's a problem that's worth solving.

I haven't tried this for a component, but in theory there's the Decorator Pattern: you could add plug-ins at run-time to intercept the control's (keyboard and mouse) input and (screen) output.

☆獨立☆ 2024-10-12 15:01:39

WPF 通过允许您将逻辑元素的视觉表示与数据模板组合来解决这个问题。 Control 类本身并没有混合功能来创建新的 Control 类,而是通过合并不同类型的内容的能力来提供可扩展点,并使用丰富的模板系统来排列和可视化内容。

换句话说,仍然可以说是“一个控制者统治一切”,但该控制者是一个骨架而不是一个完整的身体。脚手架提供了一个易于理解的框架,可以在其中添加功能,而模板系统则提供了充实控件各部分的粘合剂。


关于MEF,MEF给你带来的是扩展代码的发现和注入。它很有价值,但并不能直接解决您所描述的问题。您的问题与代码的发现关系不大,而与如何组合代码以创建连贯的总体控制的机制有关。 MEF 可以帮助执行一些粘合操作,但这只是问题中相对较小的一部分。

WPF addresses this by allowing you to composite visual representations of logical elements with data templates. Rather than mixing in features to create a new Control class, the Control class itself provides extensibility points through the ability to incorporate Content of varied types, with a rich templating system to arrange and visualize the Content.

In other words, there is still arguably 'one control to rule them all', but the control is a skeleton rather than a fully-fleshed body. The scaffolding provides a comprehensible framework within which to add features and the templating system provides the glue for fleshing out the control's parts.


Regarding MEF, what MEF buys you is discovery and injection of extension code. It's valuable, but doesn't directly address the problem you've described. Your problem has less to do with discovery of code and more to do with the mechanism of how that code is composited to create a coherent overall Control. MEF can be helpful to perform some of the gluing, but it's a relatively small part of the problem.

时光是把杀猪刀 2024-10-12 15:01:39

那么您想构建一个 Add-In 类型的框架吗?我肯定会向您推荐托管可扩展性框架。可在 .Net 4.0 中与 WinForms 或 WPF 一起使用。

Are you wanting to build an Add-In type of framework then? I would definitely point you toward Managed Extensibility Framework. Can be used in .Net 4.0 with WinForms or WPF.

太阳男子 2024-10-12 15:01:39

如果您对已经实现 mixins 的框架感兴趣以供参考,请查看 re-motion 框架 (https://www.re-motion.org/)。令人惊奇的是,在这个框架中实现 mixin 是多么容易,

以下是“Hello World”级别的参考应用程序。

使用从网站下载的程序集,在 VS2010 中创建一个类库和一个控制台应用程序,在两个项目中添加对程序集 remotion.dll 和 remotion.interfaces.dll 的引用。

using System;

namespace Domain
{
  public class Person
  {
    public Person()
    {
    }
    public Person(Person person)
    {
      FirstName = person.FirstName;
      LastName = person.LastName;
      BirthDay = person.BirthDay;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDay { get; set; }
  }
}



using System;
using Remotion.Mixins;

namespace Domain
{
  public interface IEmployeeMixin
  {
    int Salary { get; set; }
    DateTime? HireDate { get; set; }
  }

  [Extends(typeof(Person))]
  public class EmployeeMixin : IEmployeeMixin
  {
    public int Salary { get; set;  }
    public DateTime? HireDate { get; set;}
    public EmployeeMixin()
    {
      // set default values
      Salary = 1000;
      HireDate = DateTime.Now;
    }
  }
}



using Domain;
using Remotion.Reflection;
using Remotion.Mixins;

namespace ConsoleApp
{
  class Program
  {
    static void Main(string[] args)
    {
      Person p = new Person();
      p.FirstName = "John";
      p.LastName = "Doe";

      var employee = (IEmployeeMixin)ObjectFactory.Create<Person>(ParamList.Create(p));

      System.Console.WriteLine("Fullname: {0}", ((Person)employee).FirstName + " " + ((Person)employee).LastName);
      System.Console.WriteLine("Salary: {0}", employee.Salary);

      System.Console.ReadKey();
    }
  }
}

基于这个参考实现,应该很容易了解这个 mixins 是如何在这个框架中实现的。如果您想获得有关此框架(它是一个完整的 DDD 开发框架)或 mixin 的更多信息,请随时询问。我可以为您提供更多文档。

斯特凡

If you are interested in a framework that already has implemented mixins for a reference, have a look on the re-motion framework (https://www.re-motion.org/). It is amazing how easy mixins can implemented in this framework,

The following is a reference application at a "Hello World" level.

With the assemblies downloaded from the webseite, create a class library and a console app in VS2010, in both projects add references to the assmblies remotion.dll and remotion.interfaces.dll.

using System;

namespace Domain
{
  public class Person
  {
    public Person()
    {
    }
    public Person(Person person)
    {
      FirstName = person.FirstName;
      LastName = person.LastName;
      BirthDay = person.BirthDay;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDay { get; set; }
  }
}



using System;
using Remotion.Mixins;

namespace Domain
{
  public interface IEmployeeMixin
  {
    int Salary { get; set; }
    DateTime? HireDate { get; set; }
  }

  [Extends(typeof(Person))]
  public class EmployeeMixin : IEmployeeMixin
  {
    public int Salary { get; set;  }
    public DateTime? HireDate { get; set;}
    public EmployeeMixin()
    {
      // set default values
      Salary = 1000;
      HireDate = DateTime.Now;
    }
  }
}



using Domain;
using Remotion.Reflection;
using Remotion.Mixins;

namespace ConsoleApp
{
  class Program
  {
    static void Main(string[] args)
    {
      Person p = new Person();
      p.FirstName = "John";
      p.LastName = "Doe";

      var employee = (IEmployeeMixin)ObjectFactory.Create<Person>(ParamList.Create(p));

      System.Console.WriteLine("Fullname: {0}", ((Person)employee).FirstName + " " + ((Person)employee).LastName);
      System.Console.WriteLine("Salary: {0}", employee.Salary);

      System.Console.ReadKey();
    }
  }
}

Based on this reference implementation, it should be easy to get an idea, how this mixins are implemented in this framework. If you want to get more information about this framework (it is a complete DDD development framework) or the mixins, do not hesitate to ask. I can provide you with more documentation.

Stefan

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文