Wie wird das Schlüsselwort params zusammen mit den Informationen zum Aufrufer in C # verwendet?

8

Ich versuche, die C # 5.0 Caller Information zusammen mit dem Schlüsselwort C # params zu kombinieren. Die Absicht ist, einen Wrapper für ein Logging-Framework zu erstellen, und wir möchten, dass der Logger den Text wie String.Format formatiert. In früheren Versionen sah die Methode so aus:

%Vor%

Und wir nennen es so:

%Vor%

Nun möchten wir Informationen zum Anrufer erfassen und diese auch protokollieren. So wird die Signatur zu:

%Vor%

Das kompiliert nicht, weil die Parameter der letzte Parameter sein müssen. Also versuche ich das:

%Vor%

Gibt es eine Möglichkeit, das aufzurufen, ohne entweder sourceMembername bereitzustellen oder das Argument messageArgs explizit als benannten Parameter zuzuweisen? Dadurch wird der Zweck des Schlüsselworts params verfehlt:

%Vor%

Gibt es eine Möglichkeit, dies zu tun? Es scheint, als ob die "Hacky" -Methode, die die Anruferinformationen passieren, die Verwendung des Schlüsselworts params ausschließt. Es wäre genial, wenn der C # -Compiler erkennt, dass die Informationsparameter der Aufrufermitglieder überhaupt keine wirklich Parameter sind. Ich sehe keine Notwendigkeit, sie jemals explizit zu übergeben.

Meine Sicherung besteht darin, das Schlüsselwort params zu überspringen, und der Aufrufer muss die lange Signatur im letzten Beispiel verwenden.

    
Moby Disk 03.11.2014, 16:51
quelle

4 Antworten

6

Ich denke nicht, dass es genau so gemacht werden kann, wie Sie es wollen. Allerdings könnte ich an einige brauchbare Workarounds denken, die Ihnen wahrscheinlich fast die gleichen Vorteile bringen würden.

  1. Verwenden Sie einen Zwischenmethodenaufruf, um den Namen des Anrufer-Members zu erfassen. Der erste Methodenaufruf gibt einen Delegaten zurück, der wiederum aufgerufen werden kann, um die zusätzlichen Parameter bereitzustellen. Das sieht komisch aus, aber es sollte funktionieren:

    %Vor%

    Ein Nachteil hier ist, dass es möglich ist, log.Log("something") aufzurufen, in der Erwartung, dass Ihre Nachricht protokolliert wird und nichts passieren wird. Wenn Sie Resharper verwenden, können Sie dies mindern, indem Sie der Methode [Pure] ein Log() -Attribut hinzufügen, damit Sie eine Warnung erhalten, wenn jemand nichts mit dem resultierenden Objekt tut. Sie könnten diesen Ansatz auch etwas verändern und sagen:

    %Vor%
  2. Produzieren Sie Ihre Log-Nachrichten mit lambdas, und lassen Sie string.Format das Array params:

    %Vor%

    Dies ist der Ansatz, den ich normalerweise verwende, und er hat einige Seitenvorteile:

    1. Ihre Protokollmethode kann beim Erzeugen der Debug-Zeichenkette erzeugte Ausnahmen abfangen. Anstatt also Ihr System zu unterbrechen, erhalten Sie nur einen Fehler, der besagt: "Fehler beim Erstellen der Protokollnachricht: [Ausnahmedetails]".
    2. Manchmal verursacht das Objekt, das Sie an Ihre Formatzeichenfolge übergeben, möglicherweise zusätzliche Kosten, die Sie nur dann benötigen, wenn Sie sie benötigen:

      %Vor%

      Sie möchten den oben genannten Code nicht verwenden, um eine Datenbankauslösung durchzuführen, wenn die Protokollierung auf Info-Ebene nicht aktiviert ist.

    Als Randnotiz finde ich mich mit string.Format oft genug, dass ich eine Hilfsmethode erstellt habe, um die Syntax etwas zu verkürzen:

    %Vor%
StriplingWarrior 03.11.2014, 17:00
quelle
4

Um dem Vorschlag von StriplingWarrior anstelle eines Delegaten zu folgen, können Sie dies mit einer fließenden Syntax tun.

%Vor%

Dann nenne es wie

%Vor%

Logger muss nicht statisch sein, aber es war eine einfache Möglichkeit, das Konzept zu demonstrieren

    
CharlesNRice 03.11.2014 17:37
quelle
1

Nun, lassen Sie mich eine Option erwähnen; Sie können die Reflektion verwenden, um exakt denselben Namen zu erhalten, als CallMemberName . Dies wird definitiv langsamer sein. Vorausgesetzt, Sie protokollieren nicht jede Millisekunde, reicht es aus, mit dem Druck umzugehen, glaube ich.

var stackTrace = new StackTrace(); var methodName = stackTrace.GetFrame(1).GetMethod().Name;

    
Erti-Chris Eelmaa 03.11.2014 17:13
quelle
1

Ich folge gerne Jim Christophers (@beefarino) Pluralsight-Kurs, um meine eigenen Logging-Projekte einzurichten. Dazu klonge ich die ILog-Schnittstelle als ILogger, ich implementiere das - sagen wir in einer Klasse namens LoggerAdapter - und dann benutze Jim Christopher LogManager eine GetLogger (Type type) -Methode, die einen umhüllten log4net-Logger 'LoggerAdapter' zurückgibt:

%Vor%

Der nächste Schritt besteht darin, eine generische Erweiterung wie diese zu erstellen und die Anruferinformation in eine ThreadContext.Property zu setzen:

%Vor%

Wenn ich das eingerichtet habe, kann ich immer einen Logger aufrufen, bevor ich eine tatsächliche Methode schreibe, indem ich einfach Folgendes aufrufe:

%Vor%

und wenn das conversionPattern von PatternLayout für die Verwendung der Eigenschaft konfiguriert ist:

%Vor%

Sie erhalten immer eine korrekte Ausgabe mit den Anruferinformationen des ersten .Log () - Aufrufs:

%Vor%     
Ingo 01.03.2017 23:53
quelle