English 中文(简体)
为什么倾向于一种等同于明确宣布的方法?
原标题:Why isn t inlining a method equivalent to declaring it explicitly?
  • 时间:2009-10-02 10:30:07
  •  标签:

Do you have a blind spot in programming?

I mean is there a common technique or language feature that you can t really get used to. Well, I have one (or probably more than one) and mine is usage of delegate. Hands up! Who else doesn t feel comfortable with delegates? Be honest!

So what s a delegate?

Since my courses at university introduced me to C, I know about function pointers. Function pointers are handy if you want to pass methods as arguments. So in my mind a delegate is something like a function pointer. Eureka! I got it. I have not!

A concrete scenario?

I would like to remove any line from a text file that matches a regular expression. Assuming I have a collection of lines, List<T> has method RemoveAll which seems to be perfectly suitable for that purpose. RemoveAll expects an evaluation method as argument for deciding on whether to remove or leave a list element. And there it is: The function pointer!

Any code here?

public static int RemoveLinesFromFile(string path, string pattern)
{
  List<string> lines = new List<string>(File.ReadAllLines(path));
  int result = lines.RemoveAll(DoesLineMatch);
  File.WriteAllLines(path, lines.ToArray());
  return result;
}

因此,Im 寻找一种功能:DoesLineMatch,如果一条线与一种模式相匹配,则对其进行评价。

Do you see the problem?

RemoveAll expects a delegate Predicate<string> match as argument. I would have coded it like this:

private static bool DoesLineMatch(string line, string pattern)
{
  return Regex.IsMatch(line, pattern);
}

But then I m getting an error "Expected a method with bool DoesLineMatch(string) signature". What am I missing here?

Does it work at all?

这是我最后如何工作:

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;
}

我高兴的是,它发挥了作用,但我不理解它。

And what is the question?

What I did to get it working is simply inlining the method. As far as I understand inlining, it is just some kind of use-once-and-destroy-code. If you use a variable or method only once you may inline it, but inlining is always equivalent to declaring it explicitly.

www.un.org/Depts/DGACM/index_spanish.htm 是否有办法明确宣布这种方法? 我如何做?

PS:请允许我说,我的问题有些漫长。

PPS.:一俟我收到这一授权,我将从2.0跃到3.0,并学习拉姆比斯。

PPPS:以下网站:Jon s hint。 我修改了我的法典:

  int result = lines.RemoveAll(delegate(string line)
    {
      Regex regex = new Regex(pattern);
      return regex.IsMatch(line);
    });

在效率问题上,这没有什么帮助。 因此,我遵循ReSharper的建议,并将Reexspeiation移至外部:

  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(当然还有Stack Overflow)如何帮助学习。

最佳回答

您试图使用一种有以下签字的方法:

bool DoesLineMatch(string line, string pattern)

签署:

bool Predicate(string value)

它从哪里得到第二个扼杀值(模式)?

采取明确宣布的方法这样做的唯一途径就是:

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);
    }
}

然后:

public static int RemoveLinesFromFile(string path, string pattern)
{
    List<string> lines = new List<string>(File.ReadAllLines(path));
    RegexHolder holder = new RegexHolder(pattern);
    int result = lines.RemoveAll(holder.DoesLineMatch);
    File.WriteAllLines(path, lines.ToArray());
    return result;
}

这接近编篡人以匿名方式为您做的工作,因此,本部将创立一个专栏,以举办capturedtable(pattern in this case)。

(请注意,我已回避对电话<代码>Regex.Match(显示、显示)效率的任何讨论,而不是创设一个<代码>的单一实例。 Regex ... that s a different matter.

问题回答

Basically, your anonymous delegate causes compiler to do following: generate an class with unpronounceable name having a field pattern and a method similar to written by you in a delegate. Generated class looks like this:

class Matcher {
    public string Pattern;
    bool IsMatch(string value){
       return Regex.IsMatch(Pattern, value);
    }
}

阁下认为,这一类人将两种论点功能转化为一种具有一个论点的职能。

你的法典被转换成像样的东西。

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;
}

You see, runtime takes a variable from scope and binds it with function. Now you have a function with required signature that encloses additional variable. That s why delegates are called closures from CS point of view. Of course, everything mentioned can be made manually, this is just a more simple way of doing it.

希望这一帮助。

扩大此处其他部分的答复,此处为C#的一般治疗功能:

public static class DelegateUtils
{
    public static Predicate<T> ToPredicate<T>(this Func<T, Boolean> func)
    {
        return value => func(value);
    }

    public static Func<TResult> Curry<T1, TResult>(
        this Func<T1, TResult> func, T1 firstValue)
    {
        return () => func(firstValue);
    }

    public static Func<T2, TResult> Curry<T1, T2, TResult>(
        this Func<T1, T2, TResult> func, T1 firstValue)
    {
        return p2 => func(firstValue, p2);
    }

    public static Func<T2, T3, TResult> Curry<T1, T2, T3, TResult>(
        this Func<T1, T2, T3, TResult> func, T1 firstValue)
    {
        return (p2, p3) => func(firstValue, p2, p3);
    }

    // if you need more, follow the examples
}

举例来说,你将把论点的次序转到你的配对职能上,这样,你想要与之相匹配的参数就象:

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);

当然,你可以指出:

lines.RemoveAll(new Func<String, String, Boolean>(DoesLineMatch)
    .Curry("yourPattern")
    .ToPredicate());

在C# 2.0中,你可以设立一个匿名代表,你可以用来记录你的模式变数:

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

您在此所引述的是,C方案管理员通常不考虑具有不同论点的职能,而这种说法是不同的,但是,他们并没有看到,通过两条论据的指点,如果一个带有单一论据的职能的点人预期会在汇编时产生一种类型的错误,例如,这种情况会发生。 塞内加尔

“C”语只是部分地被指责:实际上,它可以通过论点和返回类型适当分类职能点。 但是,对这些类型的通知确实是宽松的,C汇编者并不总是要求这样做的,而当编者通过将所有点人(避免*)移到这里时,他们往往要走。

学习 C作为第一语言,确实教授一些坏习惯。

Wot Jon Says。

此外,在C# 3中,假定你仍然希望通过<代码>pattern<>/code>。

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

你可以宣布:

bool DoesLineMatch(string line)
{
  return Regex.IsMatch(line, pattern);
}

如果模式是你那类私人变量的话。 但很奇怪的是,你为什么可以宣布解冻线,并且对您的驱逐运动中宣布为本地的格局变量实行封闭。 易碎方法。





相关问题
热门标签