2009-06-22 22 views
5

parametresi olarak bir nesneyi çağırmak için hangi yöntemi geçirirsiniz? C# 3.5'de, aşağıdaki kodda aynı barkodlu bir işlev çağrısı olan iki yöntem var, bkz. ClientController.GetClientUsername vs clientController.GetClientGraphicalUsernameC# 3.5'de,

private static bool TryGetLogonUserIdByUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
    { 
     string username; 
     if (clientController.GetClientUsername(sClientId, out username)) 
     { 
      // ... snip common code ... 
     } 

     return false; 
    } 

    private static bool TryGetLogonUserIdByGraphicalUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
    { 
     string username; 
     if (clientController.GetClientGraphicalUsername(sClientId, out username)) 
     { 
      // ... snip common code ... 
     } 

     return false; 
    } 

bir yolu var mı (delegeler, lamda en?) Ben aramak istediğiniz clientController üzerinde hangi yöntemin de geçebilir mi?

Teşekkürler!

+0

Örnek, aynı çubuk farklı yöntem çağrıları olan kod bloklarını yeniden oluştururken karşılaştığım genel bir sorundur. Özellikle, bunları testlerde görüyorum. –

cevap

7

Elbette.

public delegate bool GetUsername(string clientID, out string username); 

Ve sonra fonksiyonu içine geçmek ve diyoruz: Sadece şöyle bir temsilci tanımlamak

private static bool TryGetLogonUserId(IGetClientUsername clientController, string sClientId, out int? logonUserId, GetUsername func) 
{ 
    string username; 
    if (func.Invoke(sClientId, out username)) 
    { 
     // ... snip common code ... 
    } 
    return false; 
} 

temsilci ile işlevini çağırmak için, bu yapacağım:

TryGetLogonUserId(/* first params... */, clientController.GetClientUsername); 
+2

func.Invoke ... zayıf stil ... – leppie

+2

Zayıf stil nedir? Delegeye geçmek mi? Sadece soruya cevap veriyordum. Delegeye ".Invoke()" diyorsunuz? Bu notasyonu tercih ediyorum çünkü bir temsilci kullandığınızı açıkça gösteriyor. –

+2

Ben Josh G ile, bu sorun için oldukça zarif bir çözüm gibi görünüyor ve eğer "func" ismini ne olursa olsun net olarak ne olduğunu açık olarak –

0

Statik olarak bakılabilen bir MethodInfo iletebilirsiniz. Ancak, bir yeniden tasarımın çağrılabileceğini kabul ediyorum.

private static readonly MethodInfo getRegularLogin = typeof(IGetClientUsername).GetMethod("GetClientUsername"); 
private static bool TryGetLogonUserIdByUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
{ 

    string username; 
    return TryGetLoginReflective(getRegularLogin, clientController, sClientId, out username, out logonUserId); 
} 

private static readonly MethodInfo getGraphicalLogin = typeof(IGetClientUsername).GetMethod("GetClientGraphicalUsername"); 
private static bool TryGetLogonUserIdByGraphicalUsername(IGetClientUsername clientController, string sClientId, out int? logonUserId) 
{ 
    string username; 
    return TryGetLoginReflective(getGraphicalLogin, clientController, sClientId, out username, out logonUserId); 
} 

private static bool TryGetLoginReflective(MethodInfo method, IGetClientUsername clientController, string sClientId, out string username, out int? logonUserId) 
{ 
    object[] args = new object[]{sClientId, null}; 
    if((bool)method.Invoke(clientController, args)) 
    { 
     // ... snip common code ... 
    } 
    logonUserId = ...; 

    username = (string)args[1]; 
    return false; 
} 
+0

Bir temsilci, bunu yansıtmaktan çok daha iyi bir yoldur. –

9

Delegeyi parametre olarak iletebilirsiniz, ancak farklı bir rotaya gitmenizi öneririm. Başka bir işlevde ortak kod içeren if ifadesinin gövdesini içine alın ve bunu her iki işlevde de adlandırın.

Visual Studio, içerik menüsünde "Refactor -> Özü Yöntemi" özelliğine sahiptir. Cesetlerden birini doldurabilir, gövdeyi seçebilir ve otomatik olarak bir yöntem çıkarmak için bu özelliği kullanabilirsiniz.

+0

Katılıyorum, bir yeniden tasarım daha iyi olurdu. – Enyra

+1

Ayrıca katılıyorum: Yeniden tasarlayın! Bu, basit olan şeyleri karmaşıklaştırmaya başladığınız tipik bir durumdur. ÖPÜCÜK. –

+0

Bu, zorunlu bir tarzda programlama için mükemmel bir öneridir (özellikle yalnızca iki olası işlev varsa), ancak aslında işlevi geçme, kısmi uygulamanın işlevsel dil özelliğinin oldukça iyi bir şekilde öykünmesine izin verir. –

1

Bir işlevin türü Funk < inParam1, InParam2, ..., returnParam> olarak yazılır. "Out" parametrelerinin düzgün "Func" tiplerinde geçirilen olmadığından emin hazırlıksız değilim, ama sen

void TryGetLogon(Func<IGetClientUsername, string, out int?, bool> f) { 
    // ... 
    f(x, y, z, a); 
} 
// ... 
TryGetLogon(TryGetLogonUserIdByGraphicalUsername); 
+2

"out" ve "ref", tür argümanlarında yasal değildir. Yeni bir temsilci türü tanımlamanız gerekir. –

0

gibi işlev yapmak gerekir nasıl basitçe bir boolean bayrak geçen dersiniz?

private static bool TryGetLogonUserIdByUsername(
    IGetClientUsername clientController, 
    string sClientId, out int? logonUserId, bool graphical) 
{ 
    string username; 
    bool gotClient = false; 

    if (graphical) 
    { 
     gotClient = clientController.GetClientGraphicalUsername(
      sClientId, out username); 
    } 
    else 
    { 
     gotClient = clientController.GetClientUsername(
      sClientId, out username); 
    } 

    if (gotClient) 
    { 
       // ... snip common code ... 
    } 

    return false; 
} 
+0

İyi fikir; Temsilci yaklaşımını tercih etmeme rağmen - aynı amacı iletmek için daha az kod –

+0

Bu seçenek verildiğinde, böyle boolean bayraklarından kaçınmayı tercih ederim.Fonksiyon isminden aradığınız işlevin işlevsel tanımını parametre listesine taşırlar. (Bu durumda, parametre listesinin sonu). Ayrıca, booleanın anlamı, çağrı alanında belirgin değildir - ne anlama geldiğini anlamak için parametre ismine bakmak zorundasınız. –