2016-04-22 23 views
3

私は、初心者/中間C#の開発者が、私は私がとに応答する必要があるXML要求を取得しています、複雑な関数と入力し、デリゲート

基本的に私はCでやって快適になるタスクを達成しようとしています対応する応答。要求/応答のペアは、よく似た構造で定義されています。

  • は "Method1Requestは" "Method1Response"
  • を受け "Method2Requestは" "Method2Response" を受信

  • ...
  • ので

、私はクラス "Method1"、 "Method2"、... "Method1Request"、 "Method2Request"、...を取得し、 "Method1Response"、 "Method2Response"を返す関数を作成するつもりです...

In関数宣言は次のようになり、付随するコードは変更されます。

  • Mtehod1Response Method1(Method1Request);
  • Method2応答メソッド2(Method2Request);
  • ...

機能応答のすべてはすぐにXMLにシリアライズされますので、理論的には、機能はすべてこのようなことができ、そしてプライベート文字列変数「レスポンス」に結果を書くことができます: 無効方法1(Method1Request) 無効方法2(Method2Request)とにかく ...

、私がやりたいことは、それが、要求の種類を見つけるために、「サンプル」XML(すでにこの作業を持っている)であります本質的には、要求に対して適切な関数を実行し、したがって正しい応答を生成するためにcase文を使用します。

したがって、これらの特定の関数を呼び出す際に同じままであるすべてのステップを実行する関数を作成する必要があります。基本的にこのような構造にされるだろう(!擬似コード!):

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以上のそれぞれのコードにすべてのコードを入力する必要があるとは思わない(うまくいけば!)のほぼ同じインスタンスをほぼ同じコードで管理する必要があります。

+0

xmlを生成するためにserializeを使用する必要はありません。代わりに動的タグがある場合は、xmlElementまたはXElement(xml linq)のいずれかを使用してxmlを生成します。 – jdweng

答えて

0

私は反射があなたの問題を解決する方法だと思います。可能な例:

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

まずあなたはリフレクション経由ですべてMethodInfo(使用可能なすべてのmethodes)を取得する必要があります:

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

今あなたが欲しいMethodeのを検索することができます。ここ

はあなたのさまざまな機能がありますあなたの利用可能な方法を通してループを使用してください。GetParameters()およびReturnTypeを使用して、パラメータの型が正しいかどうかを確認してください。あなたは試合を持っている場合は、InvokeとMethodeの呼び出し:

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)); 
    } 
} 
0

C#や他のほとんどの強く型付けされたオブジェクト指向言語は、メソッドoverloadingを実装します。ランタイムは、パラメータの型に基づいてクラスの正しいメソッドに自動的にディスパッチします。

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

私はそれが、この場合に動作する信じるが、パラメータの型に曖昧さがある場合に問題となり得る(すなわち、1種メソッドのパラメータは、別のクラスのスーパークラス)。

リフレクションは機能しますが、コンパイル時のチェックはバイパスされますので、通常は最後の手段としてのみ使用してください。

ジェネリッククラスまたはデリゲートを宣言することができます。 RequestHandler<RequestType, ReturnType>を実装し、それを具体的な実装で拡張しますが、パラメータ型に基づいたディスパッチの問題は、読者の練習として依然として残されています。

1

私は、いくつかのヘルパークラスを実装し、構成オブジェクト(単純な辞書でもよい)を使用してリクエスト処理戦略を解決するGenericsルートに行きます。

リクエストタイプが15種類以上ある場合は、対応するハンドリング戦略を実装する15種類以上の代替クラスがあることをお勧めします。

警告:ごくわずかなサンプルコードですが、頭を据えてください。デザインパターンは、することができます、あなたが興味のある場合は

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. 
} 
0

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

そして最後に、あなたのグローバルコード:シンプルな構成は、外部プロセッサクラスの静的辞書可能性が

// 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 
    } 
} 

要求パターンを型付きハンドラにリダイレクトするためにコマンドパターンで責任のチェーン(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()); 

。しかし、フレームワークがどのように構築されているか(定型化されている) Xのリクエストタイプの新しいハンドラを追加する場合は、RequestXResponseXRequestXHandlerを実装し、ディスパッチャに登録してください。

注 -システムを検証するユニットテストを作成します。私はオンラインのC#エディタでこのコードを書いた;)乾杯!

関連する問題