C# C通用处理器

C# C通用处理器,c#,generics,C#,Generics,我有一个需要标准输入组合的问题,但是有几个算法“处理器”可以解决它。输出是一个布尔值。每个处理器仅对一个特定场景有效,并且永远不会有多个处理器有效 每个处理器通过向其提供一些初始输入来确定它是否有效。如果它是有效的,那么它将根据这些初始输入计算一些信息,并将其存储——因为这些信息在最终过程中非常有用。然后,如果它是有效的,则向处理器提供额外的输入,并返回输出 如果没有处理器有效,则给出默认答案 因此,伪代码中的算法如下所示: process(inputs) for each proces

我有一个需要标准输入组合的问题,但是有几个算法“处理器”可以解决它。输出是一个布尔值。每个处理器仅对一个特定场景有效,并且永远不会有多个处理器有效

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

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

因此,伪代码中的算法如下所示:

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。如何解决这个问题?

解决这个问题的最简单方法是使用OF类型:


由于处理器是不变的,因此没有通用类型可供使用,而且由于X是在方法之外选择的,因此需要使用动态类型检查。

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


由于Processor是不变的,因此没有可以使用的公共类型,并且由于X是在方法之外选择的,因此需要使用动态类型检查。

您试图使用泛型将Processor类与其Processor info类耦合,这是有问题的。最终会出现松散耦合,您只是将对象强制转换为它们应该是的对象,而不是让泛型确保类型是正确的

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


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

您试图使用泛型将处理器类与其处理器信息类耦合,这是有问题的。最终会出现松散耦合,您只是将对象强制转换为它们应该是的对象,而不是让泛型确保类型是正确的

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


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

我认为大部分问题都不是必需的。这个问题实际上是关于泛型语法的,但在我看来,添加关于算法和伪代码的所有附加信息只是增加了噪音。你可以返回IEnumerable来解决这个问题。为什么你的处理器类在定义中没有使用t?啊,ol'协方差/逆变问题。在我的最小工作示例中,泛型没有正确实现,我现在已经纠正了它。每个处理器只能在GetResult方法中接受自己类型的ProcessorInfo。ProcessorInfo类都有不同的结构,因为它们都是不同的,所以它可以是一个接口。这个问题实际上是关于泛型语法的,但在我看来,添加关于算法和伪代码的所有附加信息只是增加了噪音。你可以返回IEnumerable来解决这个问题。为什么你的处理器类在定义中没有使用t?啊,ol'协方差/逆变问题。在我的最小工作示例中,泛型没有正确实现,我现在已经纠正了它。每个处理器只能在GetResult方法中接受自己类型的ProcessorInfo。ProcessorInfo类都有不同的结构,因为它们都是不同的,所以它可以是一个接口。太好了,谢谢!您也可以这样做:私有静态只读对象[]arr={newprocessora,newprocessorb};公共静态IEnumerable GetProcessor
其中X:ProcessorInfo{return arr.OfType;}我无法让它工作。如果您执行OfType,它将返回一个不包含任何内容的枚举,如果您尝试强制转换数组或其单个元素,则会得到InvalidCastException。我想我将不得不接受@Guffa的答案,这是一个遗憾:。@PaulRichards-这应该是可行的,但请注意,您的处理器类是不变的。如果调用GetProcessors,将得到ProcessorA的一个实例,但是,如果调用GetProcessors,您将无法获得任何匹配项,因为ProcessorA和ProcessorB由于不变性都不是Processor的实例。但您不能执行GetProcessors,因为这样做的目的是让一个process方法运行于所有处理器。@PaulRichards-在您的代码中,Process调用GetProcessors,因此该方法的调用方必须知道要使用的确切类型。太好了,谢谢!您也可以这样做:私有静态只读对象[]arr={newprocessora,newprocessorb};公共静态IEnumerable GetProcessors,其中X:ProcessorInfo{return arr.OfType;}我无法使其工作。如果您执行OfType,它将返回一个不包含任何内容的枚举,如果您尝试强制转换数组或其单个元素,则会得到InvalidCastException。我想我将不得不接受@Guffa的答案,这是一个遗憾:。@PaulRichards-这应该是可行的,但请注意,您的处理器类是不变的。如果调用GetProcessors,将得到ProcessorA的一个实例,但是,如果调用GetProcessors,您将无法获得任何匹配项,因为ProcessorA和ProcessorB由于不变性都不是Processor的实例。但您不能执行GetProcessors,因为这样做的目的是让一个process方法运行于所有处理器。@PaulRichards-在您的代码中,Process调用GetProcessors,因此该方法的调用方必须知道要使用的确切类型。我确实想到了这一点,但我之所以不这样做,是因为我不喜欢任何一种模式,在调用另一个方法之前,不能对对象调用一个方法。在调用IsValid方法之前,GetResult方法没有意义。我可能会在分类器中保留一个内部标志,它有三种状态——有效、无效和未知。如果在不知道有效性的情况下调用GetResult,它会抛出一个异常。我确实想到了这一点,但我之所以不这样做,是因为我不喜欢任何一种模式,在调用另一个方法之前,不能对一个对象调用一个方法。在调用IsValid方法之前,GetResult方法没有意义。我可能会在分类器中保留一个内部标志,它有三种状态——有效、无效和未知。如果在有效性未知时调用GetResult,则会引发异常。
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>>();
}