2011-03-26 22 views
6

Günlüğe kaydedilirken, her zaman dize değişmezlerinde dolaşırsınız. C# parametresini bir parametre olarak geçir

I ( here açıklandığı gibi) bir Expression<Func<T>> expression ileterek özellikleri, alanlar ve değişkenleri için güzel çözüldü, bu yüzden bu gibi şeyler yapabilirsiniz:

Ben yöntemle Demo kendisi için benzer bir şey yapmak istiyorum
public void Demo(string someArgument) 
{ 
    LogFrameWork.LogLine("Demo"); // goal is to get rid of these string literals 
    LogFramework.Log(() => someArgument); 
} 

:

public static void Log(Delegate method) 
{ 
    string methodName = method.Method.Name; 
    LogLine(methodName); 
} 
0123:

public void Demo(string someArgument) 
{ 
    LogFramework.Log(this.Demo); 
} 

böyle şeyler denedim

ve bu:

public static void Log(Action method) 
{ 
    string methodName = method.Method.Name; 
    LogLine(methodName); 
} 

Ama derleyici hataları bunlar gibi olsun:

Argument 1: cannot convert from 'method group' to 'System.Delegate' 
Argument 1: cannot convert from 'method group' to 'System.Action' 

Ben Func<...> ve Action<...> kullanarak aşırı bir demet tanıtmak, ama bu aşırı karmaşık geliyor.

Herhangi bir parametreye ve isteğe bağlı bir sonuca sahip herhangi bir yöntem için bunu kapamanın bir yolu var mı?

--jeroen

PS: Ben this question burada bir ilintisi olabileceğini düşünüyorum, ama beni hiç cevaplar 'aha' Daha sonra bu temsilciyi kabul temsilci tanımlayabilirsiniz :-)

+1

Sorunuzu anlıyorum, ancak, bazı AOP çerçevelerinde daha kolay ve daha genişletilebilir olacağını düşünmüyor musunuz? Çağırmada oturum açması gereken yöntemleri işaretleyen özel özellik oluşturabilirsiniz. – empi

+1

Geçmişte AOP kullandım ve derleme/bağlantı zamanlarının fırıldaklara neden oldu. .NET'in zaten daha yüksek derleme/bağlantı süreleri olduğundan, bundan kaçınmayı tercih ederim. –

+1

İfade ağaçlarını kullanarak gördüğüm bu genel sorun için her bir çözüm, parametreleri de eklemeniz gerektiğinden, aynı zamanda biraz garip olan çoklu aşırı yüklenme yaklaşımını kullandı. Manuel izleme günlüğü yazacak olursam, genellikle yöntem adını bir dize sabit olarak geçiririm ve bunları eşitlemeyi hatırlatmak için Resharper'a güvenirim. –

cevap

3

.

// resides in class Foo 
public void SomeMethod() 
{ 
    logger.Debug("Start"); 
} 

kaydedicisi alınan çıktı daha sonra olacaktır: kayıt cihazı kullanan

Kaydedici Sınıf

public void Debug(string message) 
{ 
    message = string.Format("{0}: {1}", GetCallingMethodInfo(), message); 
    // logging stuff 
} 

/// <summary> 
/// Gets the application name and method that called the logger. 
/// </summary> 
/// <returns></returns> 
private static string GetCallingMethodInfo() 
{ 
    // we should be looking at the stack 2 frames in the past: 
    // 1. for the calling method in this class 
    // 2. for the calling method that called the method in this class 
    MethodBase method = new StackFrame(2).GetMethod(); 
    string name = method.Name; 
    string type = method.DeclaringType.Name; 

    return string.Format("{0}.{1}", type, name); 
} 

yerde ortalama:

bir (sözde) örnek Foo.SomeMethod: Start

+0

+1; [çözüm] hakkında ayrıntılı bilgi için teşekkürler (http://stackoverflow.com/questions/5443521/c-pass-any-method -as-a-parameter/5443606 # 5443606) [Josh G] (http://stackoverflow.com/users/64329/josh-g) önerdi.O ne demek istediğini anladım, ama elimde daha ayrıntılı bir örneği var Gelecekteki kullanıcılara çok yardımcı olacak –

+1

Bu, birkaç yıl önce 'MS Enterprise Logging Library' kullanılarak yazdığım bir kayıt kütüphanesinden geliyor.Bu, elde etmeye çalıştığınız şeyleri çözdü, sanırım, logger'ın, logger diye adlandırılan yöntemi bilmesini istiyorsunuz. Bunun hakkında güzel bir şey 'DeclaringType 'kullanarak, sonuna kadar bir NameSpace yöntemi ile sonuçlanır. ve yöntem isminin kayıt mesajının bir parçası olarak eklenmesinden asla endişelenmenize gerek yoktur. –

+1

Cevabınızı kabul ettim çünkü arama alanında en temiz kodu oluşturuyor. Kıvrık ifadeler yok. Güzel. –

0

duygu bir parametre olarak.

public delegate void DemoDelegate(string arg); 

public void MyMethod(DemoDelegate delegate) 
{ 
    // Call the delegate 
    delegate("some string"); 
} 

Böyle MyMethod çağırabilirsiniz:

http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx

+1

Delegeleri biliyorum, ancak herhangi bir parametreye sahip herhangi bir yöntem için bana nasıl yardımcı olacağını göremiyorum. Lütfen, çok açık bir şekilde bir şey üzerinde göründüğünden ayrıntılı olarak detaylandırın :-) –

5

Ayrıca bunu başarabilirsiniz:

MyMethod(delegate(string arg) 
{ 
    // do something 
}); 

veya

void MethodThatTakesAString(string value) 
{ 
    // do something 
} 

MyMethod(MethodThatTakesAString); 

fazla bilgi için bu bağlantıya bakın System.Diagnostics.StackTrace aracılığıyla ExpressionTrees kullanmadan.

StackTrace trace = new StackTrace(); 

Ve sonra:

trace.GetFrame(0).GetMethod().Name 

MethodInfo almak ve sonra geçerli yöntemin adını veya:

trace.GetFrame(1).GetMethod().Name 

çağıran yöntemini almak için.

+0

+1; İlginç! Bunu araştıracak. Kutunun dışında düşündüğün için teşekkürler. Bu, büyük olasılıkla parametrelerin otomatik bir şekilde elde edilmesine de yardımcı olacaktır. –

+1

Bu özellikle performans açısından önemsizdir ve çerçevelerin en iyi duruma getirilme riskini taşır. –

+0

@Kirk: ifadelerin çok maliyetli olduğu da biliniyor; satır içi mi demek istiyorsun? –

0

bu deneyin:

/// <summary> 
/// Trace data event handler delegate. 
/// </summary> 
/// <returns>The data to write to the trace listeners</returns> 
public delegate object TraceDataEventHandler(); 

public static class Tracing 
{ 

    /// Trace a verbose message using an undefined event identifier and message. 
    /// </summary> 
    /// <param name="message">The delegate to call for the trace message if this event should be traced.</param> 
    [Conditional("TRACE")] 
    public static void TraceVerbose(TraceMessageEventHandler message) 
    { 
     ... your logic here 
    } 
} 

Sonra yapabilirsiniz ...

Tracing.TraceVerbose(() => String.Format(...)); 

Umarız sorunuzu doğru bir şekilde anladım ... bu sizin istediğiniz şeyi yapıyor mu? Bunun yerine, günlükçüsüne bir parametre olarak yöntemi içinde geçmesine logger çağrı yöntemini belirlemek zorunda perspektifinden bakmaya çalışmakla

5

Bu göründüğünden çok daha zor. Bence genel Func ve Action aşırı yükleri ile en iyi ihtimalle olabilirsiniz, ancak bunu ifade ağaçları ile yapmanın bir yolu var. İşte LINQPad içinde bir örnek:

public static void Log(Expression<Action> expr) 
{ 
    Console.WriteLine(((MethodCallExpression)expr.Body).Method.Name); 
} 

void Main() 
{ 
    Log(() => DoIt()); 
    Log(() => DoIt2(null)); 
    Log(() => DoIt3()); 
} 

public void DoIt() 
{ 
    Console.WriteLine ("Do It!"); 
} 

public void DoIt2(string s) 
{ 
    Console.WriteLine ("Do It 2!" + s); 
} 

public int DoIt3() 
{ 
    Console.WriteLine ("Do It 3!"); 
    return 3; 
} 

Bu çıkışlar: Ben lambdas kullanmak ve Log yöntemi çağrılırken kukla değişkenlerini belirtmek zorunda

DoIt 
DoIt2 
DoIt3

Not.

Bu, Fyodor Soikin's excellent answer tabanlıdır.

+0

Cevabınız için teşekkürler; Korkarım ki böyle bir şey olmak için ortaya çıktı, ama onaylaması iyi. –

İlgili konular