2015-07-11 88 views
2

我一直在寻找的C#泛型函数委托(Func键)功能。什么时候应该使用C#泛型函数功能<T,Tresult>?

例子:

// Instantiate delegate to reference UppercaseString method 
Func<string, string> convertMethod = UppercaseString; 
string name = "Dakota"; 

// Use delegate instance to call UppercaseString method 
Console.WriteLine(convertMethod(name)); 

我竭力想一个真实的生活场景,他们可能是在我自己的应用程序非常有用的。所以我想我会在那里提出这个问题。 \

我会非常感谢您的想法。

+2

查看IEnumerable ''Where'()''和其他extesnion方法的linq源代码,你会明白它在哪里有用以及如何使用 –

+0

可能的重复[你如何使用Func < >和Action <>在设计应用程序时?](http://stackoverflow.com/questions/1537404/how-do-you-use-func-and-action-when-designing-applications) –

+3

我结合字典和func( 'Dictionary >'在读取非托管资源时对特定键执行一些操作。 –

回答

7

假设某人需要为了报告目的而调用方法调用。出于维护原因,将时间代码放在函数内部是不可行的。

因此,通过使用该Func调用一个可以做时间的操作,不干扰:

static void Time<T>(Func<T> work) 
{ 
    var sw = Stopwatch.StartNew(); 
    var result = work(); 
    Console.WriteLine(sw.Elapsed + ": " + result); 
} 

然后用我们的函数调用它来进行定时

Time(() => { return "Jabberwocky"; }); 

结果:

00:00:00.0000926: Jabberwocky 

他再是使用相同的时间基序时间正则表达式VS string.split

var strData = "The rain in Spain"; 

Time((str) => { return Regex.Split(str, @"\s"); }, strData); 
Time((str) => { return str.Split(); },    strData); 

这里的示例性使用的Funct<T,TResult>是设置

static void Time<T,S>(Func<T,S> work, T strToSplit) 
{ 
    var sw = Stopwatch.StartNew(); 
    var result = work(strToSplit); 
    sw.Stop(); 

    var joined = string.Join(", ", result as string[]); 
    Console.WriteLine("{0} : {1}", sw.Elapsed, joined); 

} 

而且结果

00:00:00.0000232 : The, rain, in, Spain 
00:00:00.0000021 : The, rain, in, Spain 

更新2017年的答案。这不是Func,而是其不归属的兄弟Action ;我发现我做我的班记录的基本形式,我使用依赖注入从消费者像这样:

Action<string> ReportIt { get; set; } 

public void ReportStatus(Action<string> statusReporter) 
{ 
    ReportIt = statusReporter; 
} 

的想法是,状态报告是可选的,所以在我检查代码后看它是否是vialble如果是的话,我给状态:

ReportIt?.Invoke("Running - Connection initiated"); 

类的消费者称之为如

piperInstance.ReportStatus(Console.WriteLine); 

whic h后也可表现为

piperInstance.ReportStatus((str) => { Console.WriteLine(str); }); 
1

有点长的评论(制作社区的wiki)

讲解使用情况下,最好的办法是为fucntional map功能。在C#中调用Select

假设您有一个字符串列表,map将允许您更改字符串。

如你例子:

somewords.Select(Uppercase)

somewords.Select(x = Uppercase(x))

somewords.Select(x => x.ToUpper())

但不限于串来串转换。假设你想获得的所有字符串的长度的列表,你可以简单地做:

somewords.Select(x => x.Length)

上面会返回一个整数列表(或任何在你的语言使用)。

一旦你开始与其他高阶函数结合这一点,事情就变得有趣:)

让我们再回到前面的例子,但是说你想要的最长的字符串的长度。你有很多选择去做:

somewords.Select(x => x.Length).Max() 
somewords.OrderByDescending(x => x.Length).First() 
// or even 
somewords.Max(x => x.Length) 

而且可能还有一些我错过了。最后,这一切都可以帮助你表达自己的意图,而不必做很多额外的工作(如最后一个例子)。

注:

在上述所有情况下,x => x.Length可能已被取代的人得以与获取长度的任何功能,说Foo。例如

int Foo(string s) 
{ 
    return s.Length; 
} 

所以somewords.Max(Foo)是一样的。

1

刚才看到了一个有趣的现实生活中的例子:

public static List<Transaction> ReadAll(Settings settings, Func<string, FileInfo[]> getFilesOfType) 
{ 
    FileInfo[] files = getFilesOfType("CashRevenue"); 
    // does stuff with files 
} 

这是由

var transactions = FileParser.ReadAll(m_status.FilesByType) 

提供功能FilesByType作为参数调用

public FileInfo[] FilesByType (string type) 
{ 
    return result = Files.Where(f => f.Type == type) 
       .Select(f => new FileInfo(f.LocalPath)) 
       .ToArray(); 
} 

其中的文件是一个集合属性,可以使用字符串参数过滤到FilesByType

相关问题