这是来自编程测试,因此我确信有更好的方法可以做到这一点,但问题需要这个具体的答案。
我有一个方法结果,它简单地匹配谓词并返回一个bool,并且有问题的谓词检查一个字符串数组,以报告任何字符串是否超过长度为5。
static bool Result<T>(T[] values, Func<T, bool> predicate)
{
if (values.Where<T>(predicate).Count() > 0)
return true;
else
return false;
}
static bool StringLengthLessThan5(string str)
{
return str.Length < 5;
}
最后这样使用 -
bool val2 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, StringLengthLessThan5);
这可以按预期工作,但是现在我需要使用相同类型的代码,但是参数化Func以允许字符串长度的动态值,即我的Func<string,bool>
现在需要Func<string,int,bool>
< / p>
static bool StringLengthLessThanGivenNumber(string str,int length)
{
return str.Length < length;
}
或者,
static Func<string, int, bool> FuncForDynamicStringlength = (s, i) => s.Length < i;
我的问题是,本着保持新Func的调用代码相同的精神,即我仍然想使用 -
Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, StringLengthLessThanGivenNumber);
但是,我如何传递参数?
Func现在需要2个参数,第一个是字符串,第二个是int,如何传递第一个参数?我可以传递int长度来进行比较,但是我在第一个参数上难以接受。
我意识到我可以遍历我的字符串[]并在这样的foreach中调用Func(我知道在这个特定的实例中这没有意义,因为我覆盖了bool的值,但我和#39;我确定你得到了我的问题) -
foreach(string str in new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" })
{
bool val3_1 = StringLengthLessThanGivenNumber(str, 5);
}
但如果可能,我想使用我的原始代码。
答案 0 :(得分:4)
您还可以查看partial function application。您可以编写另一个函数,该函数接收带有n
参数的函数,并返回一个接受n-1
参数的函数。在内部,新函数维护对在调用时已知的某些数据的引用。例如:
static Func<string, bool> PartialApply(Func<string, int, bool> action, int length)
{
return (string str) => action(str, length);
}
在这里,您定义一个函数,它接受带有两个参数和布尔返回类型的Func
。您将使用此函数创建一个只接受一个参数的新函数:
var stringLessThan6 = PartialApply(StringLengthLessThanGivenNumber, 6);
现在,您使用变量来引用新函数,而不是在类中编写(和命名)新函数。您可以即时生成此新功能。这允许您仅通过更改参数来创建不同的变体:
var stringLessThan1 = PartialApply(StringLengthLessThanGivenNumber, 1);
var stringLessThan10 = PartialApply(StringLengthLessThanGivenNumber, 10);
var stringLessThan1000 = PartialApply(StringLengthLessThanGivenNumber, 1000);
由于您现在拥有仅接受string
并返回bool
的功能,因此您可以使用预期谓词的那些功能:
bool val2 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, stringLessThan6);
bool val2 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, stringLessThan10);
bool val3 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, stringLessThan1000);
答案 1 :(得分:3)
这是你真正想要的:
var result4 = strings.Any(s => s.Length < 6);
无需新方法。但你正在做的事情是值得的。
所以这里是你问题的确切答案,只有一些补充。
IEnumerable<T>
就是我们所需要的,所以我们接受这一点。一个string
数组实现IEnumerable<string>
,因此我们可以接受一个数组。 Count()
可能需要完成整个序列,具体取决于传入的内容。如果你要问的是它是否为0,则无需这样做。 Any()
会在谓词第一次找到匹配项时停止并返回true
。它也更简单,名称说明了它在做什么。它不像s.Where(p).Count() > 0
s.Any(p)
和f(a, n, p)
编译器都很好。 行:
a.f(n, p)
因此:
static bool Result<T1, T2>(this IEnumerable<T1> values, T2 param, Func<T1, T2, bool> predicate)
{
return values.Any(t1 => predicate(t1, param));
}
static bool StringLengthLessThanGivenNumber(string str, int len)
{
return str.Length < len;
}
这有效,但它不灵活。有些情况可能有意义:可能是基于表单中的用户输入进行过滤。谓词来自一个选择,参数来自其他地方。
但是,一般情况下,您最好将var strings = new string[] { "asdf", "a", "asdsffsfs", "wewretete", "adcv", "planxty" };
var result = strings.Result(6, StringLengthLessThanGivenNumber);
作为谓词的一部分传递,就像您最初使用它一样。看看Kenneth K对于清理这种方法的经典方法的出色答案,我应该记住这一点。
param
...
static bool Result2<T1>(this IEnumerable<T1> values, Func<T1, bool> predicate)
{
return values.Any(predicate);
}
或者更好:
var result2 = strings.Result2(s => StringLengthLessThanGivenNumber(s, 6));
答案 2 :(得分:2)
将谓词包装成lambda表达式并使用变量或常量传递所需的长度,如下所示:
int len = 5;
bool val1 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, x => StringLengthLessThanGivenNumber(x, len));
bool val2 = Result(new string[5] { "asdf", "a", "asdsffsfs", "wewretete", "adcv" }, x => StringLengthLessThanGivenNumber(x, 5));
解决此问题的另一种方法是为string
集合定义扩展方法。
public static class StringCollectionExtensions
{
public static bool HasLengthLessThan(this IEnumerable<string> collection, int length)
{
return collection.Any(x => x.Length < length);
}
}
然后你可以像这样使用它:
var testStrings = new string[5] {"asdf", "a", "asdsffsfs", "wewretete", "adcv"};
bool val3 = testStrings.HasLengthLessThan(6);