C# 为什么不是';内联一个相当于显式声明它的方法吗? 你在编程方面有盲点吗?

C# 为什么不是';内联一个相当于显式声明它的方法吗? 你在编程方面有盲点吗?,c#,delegates,c#-2.0,inline,C#,Delegates,C# 2.0,Inline,我的意思是,有没有一种共同的技巧或语言特征是你无法真正习惯的。 嗯,我有一个(或者可能不止一个),我的是使用委托。 举起手来!还有谁对代表感到不舒服?老实说 那么代表是什么? 自从我在大学的课程介绍我使用C语言以来,我就知道函数指针。 如果要将方法作为参数传递,函数指针非常方便。 在我看来,委托就像一个函数指针。尤里卡!我得到了它。我没有 一个具体的场景? 我想从文本文件中删除与匹配的任何行。 假设我有一组行,List有一个方法RemoveAll,它似乎非常适合这个目的。 RemoveAll要求

我的意思是,有没有一种共同的技巧或语言特征是你无法真正习惯的。 嗯,我有一个(或者可能不止一个),我的是使用
委托。
举起手来!还有谁对代表感到不舒服?老实说

那么代表是什么? 自从我在大学的课程介绍我使用C语言以来,我就知道函数指针。 如果要将方法作为参数传递,函数指针非常方便。 在我看来,委托就像一个函数指针。尤里卡!我得到了它。我没有

一个具体的场景? 我想从文本文件中删除与匹配的任何行。 假设我有一组行,
List
有一个方法
RemoveAll
,它似乎非常适合这个目的。
RemoveAll
要求使用求值方法作为参数,以决定是否删除或保留列表元素。 这就是:函数指针

这里有密码吗? 但是我得到了一个错误“期望一个带有'bool DoesLineMatch(string)'签名的方法”。 我错过了什么

它能用吗? 这就是我最终让它工作的方式:

public static int RemoveLinesFromFile(string path, string pattern)
{
  List<string> lines = new List<string>(File.ReadAllLines(path));
  int result = lines.RemoveAll(delegate(string line)
    {
      return Regex.IsMatch(line, pattern);
    });
  File.WriteAllLines(path, lines.ToArray());
  return result;
}
这对提高效率没有多大帮助。因此,我遵循了他的建议,将Regex实例化移到了外部范围:

  Regex regex = new Regex(pattern);
  int result = lines.RemoveAll(delegate(string line)
    {
      return regex.IsMatch(line);
    });
现在ReSharper催促我用一个方法组替换它:

  Regex regex = new Regex(pattern);
  int result = lines.RemoveAll(regex.IsMatch);

这与这里提出的答案非常相似。这不是我想要的,但我再次惊讶于ReSharper(当然还有堆栈溢出)如何帮助学习。

您正在尝试使用一种签名为:

bool DoesLineMatch(string line, string pattern)
对于有签名的代表:

bool Predicate(string value)
它从哪里获得第二个字符串值(模式)

使用显式声明的方法执行此操作的唯一方法如下:

private static bool DoesLineMatch(string line, string pattern)
{
  return Regex.IsMatch(line, pattern);
}
public sealed class RegexHolder
{
    private readonly string pattern;

    public RegexHolder(string pattern)
    {
        this.pattern = pattern;
    }

    public bool DoesLineMatch(string line)
    {
        return Regex.IsMatch(line, pattern);
    }
}
bool DoesLineMatch(string line)
{
  return Regex.IsMatch(line, pattern);
}
class Matcher {
    public string Pattern;
    bool IsMatch(string value){
       return Regex.IsMatch(Pattern, value);
    }
}
private static bool DoesLineMatch(string pattern, string line)
{
    return Regex.IsMatch(line, pattern);
}
Func<String, String, Boolean> func = DoesLineMatch;
Func<String, Boolean> predicateCandidate = func.Curry("yourPattern");
Predicate<String> predicate = predicateCandidate.ToPredicate();
lines.RemoveAll(predicate);
然后:

public static int RemoveLinesFromFile(字符串路径、字符串模式)
{
列表行=新列表(File.ReadAllLines(path));
RegexHolder支架=新RegexHolder(模式);
int结果=lines.RemoveAll(holder.DoesLineMatch);
File.writeAllines(path,lines.ToArray());
返回结果;
}
这与编译器使用匿名方法为您所做的工作非常接近——它将创建一个嵌套类来保存捕获的变量(
pattern

(注意,我避免了任何关于调用
Regex.Match(string,string)
效率的讨论,而不是创建
Regex
…的单个实例,这是另一回事。)

Wot Jon说

此外,在C#3中,您可能会选择使用lambda,假设您仍然希望将
模式
传递给您的方法:

int result = lines.RemoveAll(l => DoesLineMatch(l, pattern));

您可以这样声明:

private static bool DoesLineMatch(string line, string pattern)
{
  return Regex.IsMatch(line, pattern);
}
public sealed class RegexHolder
{
    private readonly string pattern;

    public RegexHolder(string pattern)
    {
        this.pattern = pattern;
    }

    public bool DoesLineMatch(string line)
    {
        return Regex.IsMatch(line, pattern);
    }
}
bool DoesLineMatch(string line)
{
  return Regex.IsMatch(line, pattern);
}
class Matcher {
    public string Pattern;
    bool IsMatch(string value){
       return Regex.IsMatch(Pattern, value);
    }
}
private static bool DoesLineMatch(string pattern, string line)
{
    return Regex.IsMatch(line, pattern);
}
Func<String, String, Boolean> func = DoesLineMatch;
Func<String, Boolean> predicateCandidate = func.Curry("yourPattern");
Predicate<String> predicate = predicateCandidate.ToPredicate();
lines.RemoveAll(predicate);
其中pattern是类中的私有变量。但这有点难看,这就是为什么您可以内联声明delage,并对在RemoveLinesFromFile方法中本地声明的模式变量使用闭包的原因。

在C#2.0中,您可以创建一个匿名委托,您可以使用它捕获您的模式变量:

        int result = lines.RemoveAll( delegate (string s) {return DoesLineMatch(s, pattern);});

基本上,匿名委托会使编译器执行以下操作:生成一个名称不可命名的类,该类具有字段“pattern”和类似于您在委托中编写的方法。 生成的类如下所示:

private static bool DoesLineMatch(string line, string pattern)
{
  return Regex.IsMatch(line, pattern);
}
public sealed class RegexHolder
{
    private readonly string pattern;

    public RegexHolder(string pattern)
    {
        this.pattern = pattern;
    }

    public bool DoesLineMatch(string line)
    {
        return Regex.IsMatch(line, pattern);
    }
}
bool DoesLineMatch(string line)
{
  return Regex.IsMatch(line, pattern);
}
class Matcher {
    public string Pattern;
    bool IsMatch(string value){
       return Regex.IsMatch(Pattern, value);
    }
}
private static bool DoesLineMatch(string pattern, string line)
{
    return Regex.IsMatch(line, pattern);
}
Func<String, String, Boolean> func = DoesLineMatch;
Func<String, Boolean> predicateCandidate = func.Curry("yourPattern");
Predicate<String> predicate = predicateCandidate.ToPredicate();
lines.RemoveAll(predicate);
这个类将两个参数的函数转换为一个参数的函数

您的代码被转换为

public static int RemoveLinesFromFile(string path, string pattern)
{
  List<string> lines = new List<string>(File.ReadAllLines(path));
  Matcher matcher = new Matcher(pattern);
  int result = lines.RemoveAll(matcher.IsMatch);
  File.WriteAllLines(path, lines.ToArray());
  return result;
}
public static int RemoveLinesFromFile(字符串路径、字符串模式)
{
列表行=新列表(File.ReadAllLines(path));
匹配器匹配器=新匹配器(模式);
int result=lines.RemoveAll(matcher.IsMatch);
File.writeAllines(path,lines.ToArray());
返回结果;
}
您知道,运行时从作用域中获取一个变量,并将其与函数绑定。现在您有了一个包含附加变量的具有必需签名的函数。这就是为什么从CS的角度将代理称为闭包。 当然,上面提到的一切都可以手工制作,这只是一种更简单的方法


希望这能有所帮助。

要扩展其他一些答案,这里有一个通用的C#currying函数:

然后使用currying修复第一个参数,并获取一个委托,然后将其转换为谓词,如下所示:

private static bool DoesLineMatch(string line, string pattern)
{
  return Regex.IsMatch(line, pattern);
}
public sealed class RegexHolder
{
    private readonly string pattern;

    public RegexHolder(string pattern)
    {
        this.pattern = pattern;
    }

    public bool DoesLineMatch(string line)
    {
        return Regex.IsMatch(line, pattern);
    }
}
bool DoesLineMatch(string line)
{
  return Regex.IsMatch(line, pattern);
}
class Matcher {
    public string Pattern;
    bool IsMatch(string value){
       return Regex.IsMatch(Pattern, value);
    }
}
private static bool DoesLineMatch(string pattern, string line)
{
    return Regex.IsMatch(line, pattern);
}
Func<String, String, Boolean> func = DoesLineMatch;
Func<String, Boolean> predicateCandidate = func.Curry("yourPattern");
Predicate<String> predicate = predicateCandidate.ToPredicate();
lines.RemoveAll(predicate);
Func Func=DoesLineMatch;
Func predicateCandidate=本币(“yourPattern”);
Predicate=predicateCandidate.ToPredicate();
RemoveAll(谓词);
当然,您可以将其全部内联:

lines.RemoveAll(new Func<String, String, Boolean>(DoesLineMatch)
    .Curry("yourPattern")
    .ToPredicate());
lines.RemoveAll(新函数(DoesLineMatch)
.Curry(“你的模式”)
.topreditate());

代码> 这是一个现象,C程序员通常不考虑不同类型的函数,类型不同,对于它们来说,传递一个带有两个字符串参数的函数的指针是不可能的,其中一个函数带有一个字符串参数的指针应该产生一个类型错误。在编译时,例如Algol 68

C语言对此只能负部分责任:事实上,它可以通过参数和返回类型正确地键入函数指针。但是,这些类型的表示法非常笨拙,C编译器并不总是需要这样做,而且当他们这样做的时候,程序员倾向于通过将所有指针强制转换为(void*)来绕过它


把C作为第一语言学习确实会教你一些坏习惯。

答案是咖喱:在C#中有没有一种简单的方法可以做到这一点?Jon我认为你需要删除
RegexHolder.DoesLineMatch
@Joachim,有一种方法可以在C#甚至C#2.0中使用咖喱,因为匿名方法,支持闭包,请参见我的答案。(无耻的插头:P)@Joachim:有更多的恶作剧,是的。它并不像可能的那样干净,老实说,我想让OP在开始使用currying和Lamdba之前了解我的建议。个人