C#中的复杂函数和类型委托

时间:2016-04-22 17:04:42

标签: c# types delegates

我是一名新手/中级C#开发人员,他试图完成一项我很乐意在C中完成的任务。

基本上,我收到的XML请求需要通过相应的响应进行响应。请求/响应对在如下结构中定义良好:

  • " Method1Request"收到" Method1Response"
  • " Method2Request"收到" Method2Response"
  • ...

所以,我将在我的班级中创建一个名为" Method1"," Method2",......的参数" Method1Request" ," Method2Request",...并返回" Method1Response"," Method2Response",...

在代码中,函数声明如下所示,随附的代码各不相同:

  • Mtehod1Response Method1(Method1Request);
  • Method2Response Method2(Method2Request);
  • ...

所有函数响应将立即被序列化为XML,因此,理论上,函数可以都是这样的,并且可以将结果写入私有字符串变量" response": void Method1(Method1Request) void Method2(Method2Request) ...

无论如何,我想做的是"示例" XML(已经有了这个工作),找出它是什么类型的请求,并使用case语句,基本上,在请求上运行适当的函数,因此,生成正确的响应。

因此,我需要创建一个函数来完成调用这些特定函数时保持相同的所有步骤。它基本上是这样构造的(!PSEUDO CODE!):

void ProcessRequestResponse(Type RequestType, Type ResponseType, Method MethodToRun)
{
    ...create serializers for RequestType and ResponseType...
    ...deserialize XML into RequestType...
    [ResponseType] [MethodToRun]([RequestType]);
    ...serialize ResponseType into XML...
    ...store XML as variable in class...
}

我只是不知道如何实际创建该函数并让它知道使用哪种类型运行的函数。我调查了使用代表" Func"方法,但我没有看到一种方法来定义它们与创建时未知的类型。

如何解决这个问题的任何方向都将受到赞赏。我不认为我需要为我的15个案例中的每个案例键入所有代码(希望!)并管理几乎相同的代码的相同实例。

4 个答案:

答案 0 :(得分:1)

我会去Generics路线,实现一些帮助类并使用配置对象解析请求处理策略(可以是一个简单的Dictionary)。

如果您有15种以上的请求类型,我希望有15个以上的替代类,每个类都实现相应的处理策略。

警告:只是一些一次性的示例代码,但应该给你一个良好的开端。

// Define a weakly typed interface, to be called
// by the invoking code.
public interface IRequestHandler
{
  public string HandleRequest(string xmlRequest);
}

// Defines a generic handler, accepting two type parameters, one
// for the request, one for the response.
public abstract class RequestHandler<RequestType, ResponseType> : IRequestHandler
{

  public XmlSerializer GetRequestSerializer()
  {
    return GetSerializer(typeof(RequestType));
  }

  public XmlSerializer GetResponseSerializer()
  {
    return GetSerializer(typeof(ResponseType));
    // an alternative, depending upon your deserialization library,
    // could be:
    // return GetSerializer<ResponseType>();
  }

  public XmlSerializer GetSerializer(Type dataType)
  {
    ... resolve based on type.
  }

  public string HandleRequest(string xmlRequest)
  {
    if (request == null) throw new ArgumentNullException("request");

    var requestSerializer = GetRequestSerializer();
    var typedRequest = requestSerializer.Deserialize(xmlRequest) as RequestType;
    // response is a ResponseType
    var response = ProcessRequest(typedRequest);

    var responseSerializer = GetResponseSerializer();

    return responseSerializer.Serialize(response);
  }

  protected abstract ResponseType ProcessRequest(RequestType request);
}

// One handler implementation
// you can just declare the class and RequestHandler inheritance,
// and then right click and ask Visual Studio to "Implement abstract members"
public class ActualRequestHandler : RequestHandler<ActualRequest, ActualResponse>
{
  protected ActualResponse ProcessRequest(ActualRequest request)
  {
    // ... do your processing
  }
}

// One handler implementation
public class AnotherRequestHandler : RequestHandler<AnotherRequest, AnotherResponse>
{
  protected AnotherResponse ProcessRequest(AnotherRequest request)
  {
    // ... do your processing
  }
}

简单配置可以是外部处理器类中的静态字典:

private static readonly Dictionary<Type, Func<IRequestHandler>> _strategyGetter = new Dictionary<Type, IRequestHandler>()
{
  {typeof(ActualRequest), () => new ActualRequestHandler()},
  {typeof(AnotherRequest), () => new AnotherRequestHandler()}
};

最后,您的全球代码:

Type requestType = ... your existing code processing the string request ...
Func<IRequestHandler> handlerFactoryMethod;
if(_strategyGetters.TryGetValue(requestType, out handlerFactoryMethod))
{
  var handler = handlerFactoryMethod();
  var responseString = handler(request);

  // ... do what you want with responseString ...
}
else
{
  // seems the request was not recognized.
}

答案 1 :(得分:0)

我认为反思是一种解决问题的方法。可能的例子:

以下是您的不同功能:

class Methodes
{
  bool func1(bool a) { ...}
  int func2(double b) { ... }
}

首先,您必须通过反射获取所有MethodInfo(所有可用的方法):

MethodInfo[] AvailableMethodes = typeof(Methodes).GetMethods();

现在,您可以通过可用的方法循环搜索所需的方法。使用GetParameters()ReturnType检查参数类型是否正确。如果您有匹配项,请使用Invoke

调用方法
foreach (MethodInfo AvailableMethode in AvailableMethodes)
{
  if (AvaliableMethode.ReturnType.ToString() == "TheReturnTypeYouWished") //Check your parameters also (use GetParameters)
  {
    //Call the method if you have a match
    AvaliableMethode.Invoke(AInstanceOfMethodes, YourParameter(s));
  }
}

答案 2 :(得分:0)

C#和大多数其他强类型OO语言实现方法overloading。运行时将根据参数类型自动调度到类的正确方法,例如

ResponseType1 handleRequest(RequestType1 request) { ... }    
ResponseType2 handleRequest(RequestType2 request) { ... }

我相信它会在这种情况下起作用,但如果参数类型存在歧义(即一个方法的参数是另一个方法的超类),则可能会出现问题。

反射会起作用,但它会绕过编译时检查,通常只能作为最后的手段使用。

您可以声明通用类或委托,例如RequestHandler<RequestType, ReturnType>并使用具体实现扩展它,但基于参数类型的调度问题仍然留给读者练习。

答案 3 :(得分:0)

如果设计模式让您感兴趣,那么您可以使用命令模式的责任链(COR)的风格将请求重定向到它的类型处理程序。

设计基础骨架 -

abstract class RequestBase  { }

abstract class ResponseBase { }

/// <summary>
/// Base class which will handle the request if the derived type is responsible otherwise 
/// send request to success handler in chain.
/// </summary>
internal abstract class HandlerBase<TRequest, TResponse> // contraints
    where TResponse : ResponseBase
    where TRequest : RequestBase
{
    HandlerBase<TRequest, TResponse> nextHandler;

    protected HandlerBase(HandlerBase<TRequest, TResponse> nextHandler)
    {
        this.nextHandler = nextHandler;
    }

    public TResponse Execute(TRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        try
        {
            if (this.IsResponsible(request))
                return this.InternalExecute(request);
            else
                return this.nextHandler.InternalExecute(request);
        }
        catch (Exception exception)
        {
            // log exception and rethrow or convert then throw.
            throw;
        }
    }

    protected abstract TResponse InternalExecute(TRequest request);

    protected abstract bool IsResponsible(TRequest request);
}

现在实现您的具体请求及其各自的处理程序,例如

class RequestA : RequestBase { }
class ResponseA : ResponseBase { }
class RequestB : RequestBase { }
class ResponseB : ResponseBase { }

internal class RequestAHandler : HandlerBase<RequestBase, ResponseBase>
{
    public RequestAHandler(HandlerBase<RequestBase, ResponseBase> nextHandler) : base(nextHandler)  {  }

    protected override RequestB InternalExecute(RequestBase request)
    {
        // do what ever RequestA handler shall do
        throw new NotImplementedException();
    }

    protected override bool IsResponsible(RequestBase request)
    {
        return request is RequestA;
    }
}

internal class RequestBHandler : HandlerBase<RequestBase, ResponseBase>
{
    public RequestBHandler(HandlerBase<RequestBase, ResponseBase> nextHandler) : base(nextHandler)  {  }

    protected override RequestB InternalExecute(RequestA request)
    {
        // do what ever RequestB handler shall do
        throw new NotImplementedException();
    }

    protected override bool IsResponsible(RequestBase request)
    {
        return request is RequestB;
    }
}

最后把所有东西放在一起。我们有一个COR基类,它将调用负责的处理程序来操作请求。但我们需要一个知道链或处理程序的调度程序,并且可以传递传入的请求。

class Dispatcher
{
    // cache chained instances of handlers
    private static HandlerBase<RequestBase, ResponseBase> handler = RegisterHandlers();

    public static ResponseBase Dispatch(RequestBase request)
    {
        return handler.Execute(request);
    }

    private static HandlerBase<RequestBase, ResponseBase> RegisterHandlers()
    {
        // Build chain
        HandlerBase<RequestBase, ResponseBase> contextChain = new RequestAHandler(null);
        contextChain = new RequestBHandler(contextChain);
        // register new handlers here e.g.
        // contextChain = new RequestXHandler(contextChain);

        return contextChain;
    }
}

用法 -

var response = (ResponseA)Dispatcher.Dispatch(new RequestA());

你可能会认为锅炉板代码太多了。但这就是框架的构建方式(使用boilerplating)。现在,如果您想添加一个新的请求类型为X的处理程序,您只需要实现RequestXResponseXRequestXHandler并将其注册到调度程序。

注意 - 编写单元测试以验证系统。我在网上C#编辑器上写了这段代码;)干杯!!