C#通用处理器

时间:2014-06-25 12:38:54

标签: c# generics

我遇到了一个问题,它采用了标准的输入组合,但有几种算法('处理器')可以解决它。输出是布尔值。每个处理器仅对一个特定场景有效,并且永远不会有多个处理器有效。

每个处理器通过提供一些初始输入来确定它是否有效。如果它是有效的,那么它会根据这些初始输入计算一些信息并存储它 - 因为该信息在最终过程中很有用。然后,如果它有效,则向处理器提供附加输入并返回输出。

如果没有处理器有效,则给出默认答案。

因此算法在伪代码中是这样的:

process(inputs) 
   for each processor
      determine validity and get data
      if valid
         use data to output result
      end if
   end for
  output default result
end

这是一个C#示例,它在语法上无效。它只是一个例子,在现实生活中,输入比字符串和整数更复杂。第二个输入的计算(在设计示例中为int i)在循环内重复执行,而第一个输入仅计算一次 - 因此将过程是否与处理器的结果有效分开。作为使用IEnumerable的替代方法,我们可以拥有一个数组或处理器列表。

   public class ProcessController
   {
      public static IEnumerable<Processor<X>> GetProcessors<X>() where X: ProcessorInfo
      {
         yield return new ProcessorA();
         yield return new ProcessorB();
      }

      public static bool Process<X>(String s, int i) where X : ProcessorInfo
      {
         foreach (Processor<X> processor in GetProcessors<X>())
         {
            X x = (X) processor.GetInfoIfCanProcess(s);
            if (x != null)
            {
               return processor.GetResult(x, i);
            }
         }
         return false;
      }
   }

   public abstract class Processor<T> where T: ProcessorInfo
   {
      public abstract T GetInfoIfCanProcess(String s);

      public abstract bool GetResult(T info, int i);
   }

   public interface ProcessorInfo
   {
      bool IsValid();
   }

   public class ProcessorA: Processor<ProcessorA.ProcessorInfoA>
   {
      public class ProcessorInfoA: ProcessorInfo
      {
         public bool IsValid()
         {
            //do something!
         }
      }

      public override ProcessorInfoA GetInfoIfCanProcess(string s)
      {
         //do something!
      }

      public override bool GetResult(ProcessorInfoA info, int i)
      {
         //do something!
      }
   }

   public class ProcessorB : Processor<ProcessorB.ProcessorInfoB>
   {
      public class ProcessorInfoB : ProcessorInfo
      {
         public bool IsValid()
         {
            //do something!
         }
      }

      public override ProcessorInfoB GetInfoIfCanProcess(string s)
      {
         //do something!
      }

      public override bool GetResult(ProcessorInfoB info, int i)
      {
         //do something!
      }
   }

我在GetProcessors方法中遇到语法错误:无法将类型Play.ProcessorA隐式转换为Play.Processor<X>。我怎么能绕过这个?

2 个答案:

答案 0 :(得分:2)

解决此问题的最简单方法是使用OfType

private static IEnumerable<object> GetProcessors()
{
    yield return new ProcessorA();
    yield return new ProcessorB();
}

public static IEnumerable<Processor<X>> GetProcessors<X>() where X: ProcessorInfo
{
    return GetProcessors.OfType<Processor<X>>();
}

由于Processor<X>是不变的,因此您无法使用常见类型,并且由于在方法之外选择了X,因此您需要使用动态类型检查。

答案 1 :(得分:2)

您正在尝试使用泛型将处理器类及其处理器信息类耦合,这是有问题的。你最终会得到一个松散的姿势,你只需将物体投射到它们应该的位置,而不是让仿制品确保类型是正确的。

我建议你通过将信息存储在类本身中来避免这个问题。运行处理器的代码不必知道处理器使用的信息,只需要知道处理器是否有效。

返回布尔值而不是ProcessorInfo对象,并将相关数据保留在Processor对象中。如果处理器有效,则它具有所需的数据。如果没有,当你继续尝试下一个处理器时,它将与第一步中获得的数据一起消失。