2010-09-01 26 views
93

C# içinde sayısal bir ayrım yapan bir işlev yazdım. Bu şuna benzer: Ben (? Belki) delegeleri ile bu mümkün olduğunu düşünüyorumC# Geçiş İşlevi İşlevini Geçme

public double Diff(double x, function f) 
{ 
    double h = 0.0000001; 

    return (f(x + h) - f(x))/h; 
} 

ama değilim: Ben gibi herhangi işlevinde geçmek mümkün olmak istiyorum

public double Diff(double x) 
{ 
    double h = 0.0000001; 

    return (Function(x + h) - Function(x))/h; 
} 

bunları nasıl kullanacağından emin olabilirsiniz.

Herhangi bir yardım büyük memnuniyetle karşılanacaktır.

cevap

102

kullanma eserleri yukarıda belirtilen ancak aynı görevi yapmak ve aynı zamanda adlandırma içinde niyet tanımlamak delegeler de vardır Func olarak:

public delegate double MyFunction(double x); 

public double Diff(double x, MyFunction f) 
{ 
    double h = 0.0000001; 

    return (f(x + h) - f(x))/h; 
} 

public double MyFunctionMethod(double x) 
{ 
    // Can add more complicated logic here 
    return x + 10; 
} 

public void Client() 
{ 
    double result = Diff(1.234, x => x * 456.1234); 
    double secondResult = Diff(2.345, MyFunctionMethod); 
} 
+4

3.5 ve üstü olarak, Func <> ve delegeler birbirleriyle değiştirilebilir ve bu, anonim delege ve lambdaların (anonim delege için sözdizimsel şeker olan) kullanılabileceği anlamına gelir. Bu yüzden parametreyi Func veya double yapan ve double yapan bir temsilci olarak belirleyip belirlemediğiniz farketmez. Adlandırılmış bir temsilci tarafından sağlanan tek gerçek avantaj, xml-doc yorumlarının eklenmesidir; Tanımlayıcı isimler, tür yerine parametre adı kadar kolay uygulanır. – KeithS

+3

Yöntem prototipinin kodu Func 'dan daha okunabilir hâle getirdiğini iddia ediyorum - yalnızca kodun okunabilir olmasını ve lambdaları kodun içinden geçirmenizi engellemediğinizi söylediğiniz gibi adlandırmak değil. –

+0

Delege türünün isimlendirmesi kod açıklığı için çok önemliyse, çoğu durumda bir arabirime ve uygulamalara yöneleceğimi düşünüyorum. –

138

Net (v2 ve üstü) sürümlerinde delegeler çok kolay şekilde geçiş işlevleri gerçekleştiren birkaç genel tür vardır.

Dönüş tipli işlevler için, Func <> vardır ve dönüş türü olmayan işlevler için Eylem <> vardır.

Hem Func hem de Action öğesinin 0 ila 4 parametresi alacağı bildirilebilir. Örneğin, Func < çift, int> bir parametre olarak bir çift alır ve bir int döndürür. Eylem < çift, çift, çift> parametrelerin üç çiftini alır ve hiçbir şey (void) döndürür.

public double Diff(double x, Func<double, double> f) { 
    double h = 0.0000001; 

    return (f(x + h) - f(x))/h; 
} 

Ve sonra sadece Elinden Func imzasını veya İşlem uyan fonksiyonun adını vererek, bu nedenle diyoruz:

Yani bir Func çekmek için Diff fonksiyonunu ilan edebilir

double result = Diff(myValue, Function); 

hatta lambda sözdizimi ile-line fonksiyonu yazabiliriz:

double result = Diff(myValue, d => Math.Sqrt(d * 3.14)); 
+23

, hem 'Func 've' Eylem', [16'ya kadar] (http://msdn.microsoft.com/en-us/library/dd402862.aspx) parametrelerine izin verecek şekilde güncellendi. –

+4

Yapılması gereken gerçekten harika bir şey, 'Func ' döndüren, yani fonksiyonun sayısal olarak hesaplanan giriş fonksiyonunun ilk türevi. 'return x => (f (x + h) - f (x))/h;' Giriş işlevinin türevini döndüren bir aşırı yük bile yazabilirsiniz. – Ani

7
public static T Runner<T>(Func<T> funcToRun) 
{ 
    //Do stuff before running function as normal 
    return funcToRun(); 
} 

Kullanımı: .NET 4'te

var ReturnValue = Runner(() => GetUser(99)); 
+0

Merak ediyorum, neden jenerik tip parametresi? – kdbanman

+1

Bu hatayı alıyorum: 'Runner (Func )' yöntemine ilişkin argüman türü, kullanımdan çıkarılamıyor. Tip argümanlarını açıkça belirtmeyi deneyin. – DermFrench

+0

"funcToRun" yöntem imzanız nedir? – kravits88