c# - 如何执行多个“mixins”操作正确使用接口和/或抽象类

发布于 2024-08-17 06:54:50 字数 2066 浏览 2 评论 0原文

我希望能够定义一些对象并将一些“行为”附加到该对象,其中实现是在行为中而不是在对象中。类似 Rails:acts_as_taggable。作为一个具体的例子,我想说任务是可以被标记的。除了通过......接口“启用”行为之外,我不想在有关标签的任务中编写任何代码?这就是我的问题。您不能将实现放入接口中。我不想用所有可能的实现来污染我的 BaseObject [抽象?] 类。

对象:任务、注释

行为:可标记、可通过电子邮件发送、可打印、可推迟(

任务可以标记、通过电子邮件发送、打印和推迟。 注释可以被标记、通过电子邮件发送、打印,但不能推迟。

baseobject

public class BaseObject
{
    Guid ID { get; set; }
}

tag.cs​​

public class Tag : BaseObject
{
    public Guid Id { get; set; }
    public String Title { get; set; }
}

itaggable.cs

public interface ITaggable 
{
    void AddTag(Tag tag);
    ... other Tag methods ... 
}

task.cs

public class Task : BaseObject, ITaggable, IEmailable, IPrintable
{
    Task specified functionality... nothing about "taggging"
}

note.cs

..

TagCollection.cs

public class TagCollection : List<Tag>
{
    public string[] ToStringArray()
    {
        string[] s = new string[this.Count];
        for (int i = 0; i < this.Count; i++)
            s[i] = this[i].TagName;
        return s;
    }

    public override string ToString()
    {
        return String.Join(",", this.ToStringArray());
    }

    public void Add(string tagName)
    {
        this.Add(new Tag(tagName));
    }

ITaggable 的实现看起来像这样

{
    private TagCollection _tc;
    private TagCollection tc
    {
        get
        {
            if (null == _tc)
            {
                _tc = new TagCollection();
            }
            return _tc;
        }
        set { _tc = value; }
    }

    public void AddTag(Tag tag)
    {
        tc.Add(tag);
    }

    public void AddTags(TagCollection tags)
    {
        tc.AddRange(tags);
    }

    public TagCollection GetTags()
    {
        return tc;
    }
}

,那么正确/最好的方法是什么?

贾森

I want to be able to define some objects and attach some "behaviors" to that object where the implementation is in the behavior not in the object. Rails-like: acts_as_taggable. As a concrete example, I want to say that Tasks can be Tagged. I don't want to have to code anything in Task about Tags beyond "enabling" the behavior via ... an interface? Therein lies my question. You can't put the implementation in an interface. I don't want to pollute my BaseObject [abstract?] class with all of the possible implementations.

Objects: Task, Note

Behaviors: Taggable, Emailable, Printable, Deferrable (

A Task may be tagged, emailed, printed, and deferred.
A Note may be tagged, emailed, printed, but not deferred.

baseobject

public class BaseObject
{
    Guid ID { get; set; }
}

tag.cs

public class Tag : BaseObject
{
    public Guid Id { get; set; }
    public String Title { get; set; }
}

itaggable.cs

public interface ITaggable 
{
    void AddTag(Tag tag);
    ... other Tag methods ... 
}

task.cs

public class Task : BaseObject, ITaggable, IEmailable, IPrintable
{
    Task specified functionality... nothing about "taggging"
}

note.cs

...

TagCollection.cs

public class TagCollection : List<Tag>
{
    public string[] ToStringArray()
    {
        string[] s = new string[this.Count];
        for (int i = 0; i < this.Count; i++)
            s[i] = this[i].TagName;
        return s;
    }

    public override string ToString()
    {
        return String.Join(",", this.ToStringArray());
    }

    public void Add(string tagName)
    {
        this.Add(new Tag(tagName));
    }

Implementation of ITaggable looks something like

{
    private TagCollection _tc;
    private TagCollection tc
    {
        get
        {
            if (null == _tc)
            {
                _tc = new TagCollection();
            }
            return _tc;
        }
        set { _tc = value; }
    }

    public void AddTag(Tag tag)
    {
        tc.Add(tag);
    }

    public void AddTags(TagCollection tags)
    {
        tc.AddRange(tags);
    }

    public TagCollection GetTags()
    {
        return tc;
    }
}

So what's the correct/best way to do this?

Jason

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

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

发布评论

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

评论(5

卸妝后依然美 2024-08-24 06:54:50

嗯,有很多方法,具体取决于您想要如何实施。在您的示例中,最好按照以下方式做一些事情:

public interface IBehavior
{
    ... common behavior methods like maybe
    bool Execute(object value)
}

public class Taggable : IBehavior
{
   ... tag specific items
   public bool Execute(object value) { ... }
}

public class Note
{
   public List<IBehavior> Behaviors { get; set; }
   public void ProcessNote()
   {
       this.Behaviors(d=>d.Execute(this));
   }
}

这种变体将允许您始终添加更多行为,而不必对类结构进行任何重大更改,例如在您想要支持的每个类上实现接口新的行为。您可能想要想出您的行为类中的公共对象,以使其更容易用于您的场景。因此,您可以使用泛型来进行更多类型化的定义。

您可能还想查看装饰器模式,以便为您提供更多想法。

Well there are lots of ways depending on how you want to implement. In your example it might be better to do something along the lines of this:

public interface IBehavior
{
    ... common behavior methods like maybe
    bool Execute(object value)
}

public class Taggable : IBehavior
{
   ... tag specific items
   public bool Execute(object value) { ... }
}

public class Note
{
   public List<IBehavior> Behaviors { get; set; }
   public void ProcessNote()
   {
       this.Behaviors(d=>d.Execute(this));
   }
}

This variation would allow you to always add more behaviors without having to do any drastic changes to your class structures either like implementing an interface on every class that you want to support the new behavior. You may want to come up with what your common object would be amongst your behavior class to make it easier to use for your scenario though. So you could use generics to allow you to do a more typed definition.

You might want to look at the Decorator pattern as well to give you even more ideas.

世界等同你 2024-08-24 06:54:50

不幸的是,您必须向您的类(基类或后代)添加一些代码。

但是,您可以将“可标记”类作为私有成员,并将所有方法调用传递给该成员对象,但您仍然需要实现该接口。

像这样的东西:

interface ITaggable {
    void AddTag(String tag);
}

class TaggableImplementation : ITaggable {
    private Hashset<String> tags = new Hashset<String>();
    public void AddTag(String tag) { tags.Add(tag); }
}

class TaggableClass : ITaggable {
    private ITaggable taggable = new TaggableImplementation();

    public void AddTag(String tag) { taggable.AddTag(tag); }
}

Unfortunately you're going to have to add some code to your classes, either the base class or the descendant.

You can, however, get away with the "taggable" class being a private member, and just passing on all method calls to that member object, but you still need to implement the interface.

Something like this:

interface ITaggable {
    void AddTag(String tag);
}

class TaggableImplementation : ITaggable {
    private Hashset<String> tags = new Hashset<String>();
    public void AddTag(String tag) { tags.Add(tag); }
}

class TaggableClass : ITaggable {
    private ITaggable taggable = new TaggableImplementation();

    public void AddTag(String tag) { taggable.AddTag(tag); }
}
挥剑断情 2024-08-24 06:54:50

要使用 Visual Studio 的内置 T4 代码生成技术创建 mixins,您可以查看 http://code.logos.com/blog/2009/04/creating_mixins_with_t4_in_visual_studio.html

To create mixins using Visual Studio's built-in T4 code-generation technique, you may take a look at http://code.logos.com/blog/2009/04/creating_mixins_with_t4_in_visual_studio.html

霞映澄塘 2024-08-24 06:54:50

我通过使用部分类,并将源代码从模板文件复制到部分类源文件中,在 C# 中实现了 mixin。如果你接受一些限制,它的效果会很好。我尝试使用 T4 预处理器自动生成源文件,但它有点太麻烦了,所以我编写了一个相当简约的工具来从比 T4 脚本更容易生成的模板文件中复制代码。只要稍加小心,您甚至可以在编写模板时使用 Intellisense。

对于该工具,请查看:

http://myxin.codeplex.com/

例如,查看 Streambolics.Gui 的源代码:

http://streambolicscore.codeplex.com/

I've implemented mixins in C# by using partial classes, and copying source code from a template file into partial class source files. If you accept a few limitations, it works quite well. I tried the T4 pre-processor to automatically generate the source files, but it was a little too cumbersome, so I've written a - quite minimalistic - tool to copy code from template files that are much easier to generate than T4 scripts. With a little care, you can even use Intellisense when writing your template.

For the tool, have a look at:

http://myxin.codeplex.com/

For an example, have a look at the source code for Streambolics.Gui at:

http://streambolicscore.codeplex.com/

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