2011-01-05 6 views
0

Mein Code sieht hässlich aus, und ich weiß, es muss ein besserer Weg zu tun, sein, was ich tue:Helfen Sie mir mit dem Schlüsselwort out dieses verrückte Lambda aufzuräumen

private delegate string doStuff(
    PasswordEncrypter encrypter, RSAPublicKey publicKey, 
    string privateKey, out string salt 
); 

private bool tryEncryptPassword(
    doStuff encryptPassword, 
    out string errorMessage 
) 
{ 
    ...get some variables... 
    string encryptedPassword = encryptPassword(encrypter, publicKey, 
     privateKey, out salt); 
    ... 
} 

dieses Zeug so weit doesn‘ Mich nicht stören. Es ist, wie ich tryEncryptPassword aufrufen, die so hässlich aussieht und hat Vervielfältigung, weil ich es aus zwei Methoden aufrufen:

public bool method1(out string errorMessage) 
{ 
    string rawPassword = "foo"; 
    return tryEncryptPassword(
     (PasswordEncrypter encrypter, RSAPublicKey publicKey, 
      string privateKey, out string salt) => 
      encrypter.EncryptPasswordAndDoStuff(// Overload 1 
       rawPassword, publicKey, privateKey, out salt 
      ), 
     out errorMessage 
    ); 
} 

public bool method2(SecureString unencryptedPassword, 
    out string errorMessage) 
{ 
    return tryEncryptPassword(
     (PasswordEncrypter encrypter, RSAPublicKey publicKey, 
      string privateKey, out string salt) => 
      encrypter.EncryptPasswordAndDoStuff(// Overload 2 
       unencryptedPassword, publicKey, privateKey, out salt 
      ), 
     out errorMessage 
    ); 
} 

Zwei Teile der Hässlichkeit:

  • ich ausdrücklich alle der Parameterliste müssen Typiert den Lambda-Ausdruck wegen des einzigen Parameters out.
  • Die beiden Überladungen von EncryptPasswordAndDoStuff nehmen alle die gleichen Parameter außer dem ersten Parameter, der entweder ein string oder ein SecureString sein kann. So sind method1 und method2 ziemlich identisch, sie rufen nur verschiedene Überladungen von EncryptPasswordAndDoStuff.

Irgendwelche Vorschläge?

Edit (Lösung): endete ich Jeffs Vorschlag mit und zur Änderung der Überlastung von EncryptPasswordAndDoStuff eine Instanz von EncryptionResult zurückzukehren. Dann brauchte ich nicht explizit delegate definiert, und ich den folgenden Code:

private bool tryEncryptPassword(KeysAndEncrypter keys, 
    Func<EncryptionResult> encryptPassword, 
    out string errorMessage 
) { ... } 

private class KeysAndEncrypter 
{ 
    public RSAPublicKey PublicKey { get; set; } 
    public string PrivateKey { get; set; } 
    public PasswordEncrypter Encrypter { get; set; } 
} 

Und hier war der Inhalt von method1, mit method2 sehr ähnlich zu sein:

string rawPassword = "foo"; 
KeysAndEncrypter keys = getEncryptionKeys(); 
return tryEncryptPassword(keys,() => 
    keys.Encrypter.EncryptPasswordAndDoStuff(
     rawPassword, keys.PublicKey, keys.PrivateKey 
    ), 
    out errorMessage 
); 
+0

Haben beide Überladungen von EncryptPasswordAndDoStuff eine ähnliche Funktionalität? Und verwenden Sie den Bool-Rückgabewert von Methode1 und Methode2? –

+0

@Ilya: Ja, beide 'EncryptPasswordAndDoStuff' Überladungen machen dasselbe; in der Tat rufen sie nur zwei verschiedene Überladungen einer 'Verschlüsseln' Methode auf, sowie einige andere Sachen. Die 'bool' Rückgabe von' method1' und 'method2' wird von den Aufrufern verwendet, also ist es notwendig. –

Antwort

5

Sie ein vorstellen könnte neue Art der Delegierten Rückgabewert darstellen:

public class EncryptionResult { 
    public string EncryptedValue { get; set; } 
    public string Salt { get; set; } 
} 

... und die Delegierten so zu etwas ändern:

private delegate EncryptionResult doStuff(
    PasswordEncrypter encrypter, 
    RSAPublicKey publicKey, 
    string privateKey); 
+0

Das funktioniert und macht definitiv den Aufruf von 'tryEncryptPassword' sauberer, aber ich muss mehr repetitive Sachen in den Lambdas machen. Ich werde meine Frage aktualisieren, damit der Code Ihre Änderungen anzeigt. –

1

Jeffs Vorschlag ist vernünftig. Sie könnten auch einfach eine Tuple<string, string> verwenden, wenn Sie nicht jedes Mal einen neuen Typ definieren möchten, wenn Sie einen out-Parameter benötigen.

Ein anderer Vorschlag wäre, einen anderen Delegaten zu übergeben, um den Fehler zu erhalten, anstatt einen out-Parameter zu verwenden.

private bool tryEncryptPassword(
    doStuff encryptPassword, 
    Action<string> setError 
) 

public bool method1(Action<string> setError) { 
    ... 
    tryEncryptPassword(..., ..., ..., setError); 
} 

Bevor method1 aufrufen, können Sie Ihre setError einer lokalen Variablen zuweisen.

string error; 
Action<string> setError = str => error = str; 
method1(setError);   
0

Wenn Sie auch keinen benutzerdefinierten Typ erstellen möchten, können Sie hier ein Tupel zurückgeben.

private delegate Tuple<string, string> doStuff(
    PasswordEncrypter encrypter, 
    RSAPublicKey publicKey, 
    string privateKey); 

innerhalb doStuff, nur erstellen und ein Tupel zurück:

Tuple<string, string> result = new Tuple<string, string>(EncryptedValue, Salt); 
return result; 
2

Warum überhaupt mit dem verrückten Lambda die Mühe machen?

public bool Method1(out string errorMessage) 
{ 
    return TryEncryptPassword("foo", out errorMessage); 
} 

public bool Method2(SecureString password, out string errorMessage) 
{ 
    return TryEncryptPassword(password, out errorMessage); 
} 

private bool TryEncryptPassword(string password, out string errorMessage) 
{ 
    GetSomeVariables(); 
    string encryptedPassword = encrypter.EncryptPasswordAndDoStuff(
      password, publicKey, privateKey, out salt); 
    DoMoreStuff(); 
    // ... 
} 

private bool TryEncryptPassword(SecureString password, out string errorMessage) 
{ 
    GetSomeVariables(); 
    string encryptedPassword = encrypter.EncryptPasswordAndDoStuff(
      password, publicKey, privateKey, out salt); 
    DoMoreStuff(); 
    // ... 
} 

private void GetSomeVariables() { /* ...get some variables... */ } 

private void DoMoreStuff() { /* ... */ } 
+0

Meine '...' waren irreführend: Es gibt eine Menge Code über und unter dem Aufruf von 'EncryptPasswordAndDoStuff'. Vielleicht sollte ich mich jedoch auf das Refactoring konzentrieren, um es kürzer und einfacher zu machen, und dann tun, was Sie vorschlagen. –

+0

Mit den neuen Infos bekommt das auch meine Stimme! –

+0

@Sarah: Sie könnten den freigegebenen Code vermutlich in separate private Methoden exportieren und sie von beiden Überladungen 'TryEncryptPassword' aufrufen. Diese Überlastungen wären dann praktisch leer. – LukeH

Verwandte Themen