C# 使用标记类控制逻辑流

C# 使用标记类控制逻辑流,c#,.net,C#,.net,我一直在浏览一些代码,看到我的一位同事正在使用“标记类”来控制程序逻辑(参见下面的人为示例)。它似乎工作得很好,代码读起来也很好,但它只是有点异味 namespace ConsoleApplication4983 { public class MyClass { static void Main() { var c = new MyClass(); c.DoSomething(new Sequenti

我一直在浏览一些代码,看到我的一位同事正在使用“标记类”来控制程序逻辑(参见下面的人为示例)。它似乎工作得很好,代码读起来也很好,但它只是有点异味

namespace ConsoleApplication4983
{
    public class MyClass
    {
        static void Main()
        {
            var c = new MyClass();
            c.DoSomething(new Sequential());
            c.DoSomething(new Random());
        }

        public void DoSomething(ProcessingMethod method)
        {
            if (method is Sequential)
            {
                // do something sequential
            }
            else if (method is Random)
            {
                // do something random
            }
        }
    }

    public class ProcessingMethod {}
    public class Sequential : ProcessingMethod {}
    public class Random : ProcessingMethod {}
}
达到同样效果的更好方法是什么?枚举?属性?

标记接口是更好的做法,因为它们提供了更大的灵活性

但是在这种情况下,我认为虚拟分派是一个更好的解决方案

using System;

namespace ConsoleApplication4983
{
    public class MyClass
    {
        static void Main()
        {
            var c = new MyClass();
            c.DoSomething(new Sequential());
            c.DoSomething(new Random());
        }

        public void DoSomething(ProcessingMethod method)
        {
            method.Foo();
        }
    }

    public class ProcessingMethod
    {
        public virtual void Foo() { }
    }
    public class Sequential : ProcessingMethod
    {
        public override void Foo() { }
    }
    public class Random : ProcessingMethod
    {
        public override void Foo() { }
    }
}

他几乎就在那里,但不完全在那里,这可能就是你所看到的。类型上的if语句是臭味。do something应该在ProcessingMethod基类上,扩展它的每个类型都应该有自己的版本

public void DoSomething(ProcessingMethod method)    {
   method.DoSomething();
}

将处理逻辑委托给特定的子类如何
ProcessingMethod
将具有由每个子类实现的一些抽象方法

public void DoSomething(ProcessingMethod method)
{
  method.Process();
}

public abstract class ProcessingMethod
{
  public abstract void Process();
}

public class Sequental : ProcessingMethod
{
  public override void Process()
  {
    // do something sequential
  }
}

public class Random : ProcessingMethod
{
  public override void Process()
  {
    // do something random
  }
}

是的,这闻起来很难闻。如果你想做一些平行的事情:

public class Parallel : ProcessingMethod{}

然后,您将不得不更改许多代码

您要做的是将其替换为一个。策略定义了如何完成某件事,即算法

public interface IProcessingMethod
{
    void Process();
}

public class SequentialProcess : IProcessingMethod
{
    public void Process( IProcessable obj )
    {
         do something sequentially with the obj
    }
}

public class ParallelProcess : IProcessingMethod
{
    public void Process( IProcessable obj )
    {
        do something in parallel with the obj
    }
}

public interface IProcessable
{
    void Process( IProcessingMethod method );
}

public class MyClass : IProcessable
{
     public void Process( IProcessingMethod method )
     {
         method.Process( this );
     }
}

...

var obj = new MyClass();
obj.Process( new SequentialProcess() );

现在,如果我有一种新类型的ProcessingMethod,我只需要为该方法创建类,并更改确定将什么处理方法注入我的IProcessable对象的Process method的代码。

框架设计指南书建议不要使用标记接口(可能还有标记类),首选属性intead。话虽如此,这本书还是继续说,使用
is
(正如您所做的)比使用反射检查属性要快得多。

我看到这个问题很老,但我觉得所有的答案都没有抓住重点

如果该示例充分说明了所需功能的范围,那么此处使用的适当构造将是枚举类型。枚举类型是值类型;它们的功能本质上类似于命名的数值常量,具有强大的IDE自动完成支持。下面是修改为使用枚举类型的示例:

namespace ConsoleApplication4983
{
    public class MyClass
    {
        static void Main()
        {
            var c = new MyClass();
            c.DoSomething(ProcessingMethod.Sequential);
            c.DoSomething(ProcessingMethod.Random);
        }

        public void DoSomething(ProcessingMethod method)
        {
            if (method == ProcessingMethod.Sequential)
            {
                // do something sequential
            }
            else if (method == ProcessingMethod.Random)
            {
                // do something random
            }
        }
    }

    public enum ProcessingMethod
    {
        Sequential,
        Random
    }
}
其他答案是参考更复杂的模式。我认为他们对“标记类”这个词读得太多了。有时,策略模式、虚拟调度等是一种很好的方法,但在这种情况下,我认为枚举是对代码进行的最简单的改进