当它不是静态的时,如何使用现有方法代替lambda? [英] How to use existing method instead of lambda when it's not static?

查看:128
本文介绍了当它不是静态的时,如何使用现有方法代替lambda?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这必须是重复的,但我还没有找到.我发现了这个问题是相关的,因为它回答了为什么建议使用方法组而不是lambda的原因.

This must be a duplicate but i haven't found it. I've found this question which is related since it answers why it's recommended to use a method group instead of a lambda.

但是如果该方法不在当前类中并且该方法不是static,该如何使用现有方法组而不是lambda?

But how do i use an existing method group instead of a lambda if the method is not in the current class and the method is not static?

说我有一个要转换为字符串的整数列表,我可以使用List.ConvertAll,但是我需要将Converter<int, string>传递给它:

Say i have a list of ints which i want to convert to strings, i can use List.ConvertAll, but i need to pass a Converter<int, string> to it:

List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(i => i.ToString());

这可行,但是它使用lambda创建了不必要的匿名方法.因此,如果Int32.ToString是静态的并采用int,我可以写:

This works, but it creates an unnecessary anonymous method with the lambda. So if Int32.ToString would be static and would take an int i could write:

List<string> strings = ints.ConvertAll<string>(Int32.ToString);

但是那不能编译-当然.那么我怎么仍然可以使用方法组呢?

But that doesn't compile - of course. So how can i use a method group anyway?

如果我要创建这样的实例方法

If i'd create an instance method like this

string FooInt(int foo)
{
    return foo.ToString();
}

我可以使用strings = ints.ConvertAll<string>(FooInt);,但这不是我想要的.我不想创建新方法只是为了能够使用现有方法.

i could use strings = ints.ConvertAll<string>(FooInt);, but that is not what i want. I don't want to create a new method just to be able to use an existing.

推荐答案

框架中有一个静态方法,可用于将任何集成数据类型转换为字符串,即Convert.ToString:

There is an static method in the framework, that can be used to convert any integrated data type into a string, namely Convert.ToString:

List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(Convert.ToString);

由于Convert.ToString的签名也是已知的,因此您甚至可以消除显式的目标类型参数:

Since the signature of Convert.ToString is also known, you can even eliminate the explicit target type parameter:

var strings = ints.ConvertAll(Convert.ToString);

这有效.但是,即使ReSharper告诉您一些不同的内容,我也希望使用lambda表达式. ReSharper有时会优化太多恕我直言.它阻止开发人员考虑他们的代码,特别是在可读性方面.

This works. However, I'd also prefer the lambda-expression, even if ReSharper tells you something different. ReSharper sometimes optimizes too much imho. It prevents developers from thinking about their code, especially in the aspect of readability.

根据Tim的评论,在这种特殊情况下,我将尝试解释lambda和静态方法组调用之间的区别.因此,我首先研究了mscorlib反汇编,以了解int到字符串的转换是如何工作的. Int32.ToString方法在System命名空间的Number类中调用一个外部方法:

Based on Tim's comment, I will try to explain the difference between lambda and static method group calls in this particular case. Therefor, I first took a look into the mscorlib disassembly to figure out, how int-to-string conversion exactly works. The Int32.ToString method calls an external method within the Number-class of the System namespace:

[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecuritySafeCritical]
public string ToString(IFormatProvider provider)
{
    return Number.FormatInt32(this, null, NumberFormatInfo.GetInstance(provider));
}

静态Convert.ToString成员除了对参数调用ToString以外无其他操作:

The static Convert.ToString member does nothing else than calling ToString on the parameter:

[__DynamicallyInvokable]
public static string ToString(int value)
{
    return value.ToString(CultureInfo.CurrentCulture);
}

从技术上讲,如果您像在问题中所做的那样编写自己的静态成员或扩展名,则没有任何区别.那这两行之间有什么区别?

Technically there would be no difference, if you'd write your own static member or extension, like you did in your question. So what's the difference between those two lines?

ints.ConvertAll<string>(i => i.ToString());
ints.ConvertAll(Convert.ToString);

而且-从技术上讲-没有区别.第一个示例创建一个匿名方法,该方法返回一个字符串并接受一个整数.使用整数的实例,它将调用它的成员ToString.第二种方法相同,不同之处在于该方法不是匿名的,而是框架的集成成员.

Also - technically - there is no difference. The first example create's an anonymous method, that returns a string and accepts an integer. Using the integer's instance, it calls it's member ToString. The second one does the same, with the exception that the method is not anonymous, but an integrated member of the framework.

唯一的区别是第二行较短,并且为编译器节省了一些操作.

The only difference is that the second line is shorter and saves the compiler a few operations.

但是为什么不能直接调用非静态ToString?

But why can't you call the non-static ToString directly?

让我们看一下ListConvertAll方法:

public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
    if (converter == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
    }

    List<TOutput> list = new List<TOutput>(this._size);

    for (int i = 0; i < this._size; i++)
    {
        list._items[i] = converter(this._items[i]);
    }

    list._size = this._size;
    return list;
}

该列表遍历每个项目,以该项目作为参数调用转换器,并将结果复制到一个新列表中,最后返回该列表.

The list iteraterates over each item, calls the converter with the item as an argument and copys the result into a new list which it returns in the end.

因此,这里唯一的关系是显式调用的converter.如果可以将Int32.ToString传递给该方法,则编译器将不得不决定在循环内调用this._items[i].ToString().在这种特定情况下,它可以工作,但是对于编译器而言,这太聪明了".类型系统不支持这种代码转换.相反,转换器是一个对象,描述了可以从被调用者的范围调用的方法.这是现有的静态方法(如Convert.ToString),还是匿名表达式(如lambda).

So the only relation here is your converter that get's called explicitly. If you could pass Int32.ToString to the method, the compiler would have to decide to call this._items[i].ToString() within the loop. In this specific case it would work, but that's "too much intelligence" for the compiler. The type system does not support such code conversions. Instead the converter is an object, describing a method that can be called from the scope of the callee. Either this is an existing static method, like Convert.ToString, or an anonymous expression, like your lambda.

是什么原因导致基准测试结果出现差异?

这很难猜.我可以想象两个因素:

That's hard to guess. I can imagine two factors:

  1. 评估lambda可能会导致运行时开销.
  2. 可以优化框架调用.

最后一点尤其意味着,JITer能够内联调用,从而获得更好的性能.但是,这些只是我的假设.如果有人可以澄清这一点,我将不胜感激! :)

The last point especially means, that the JITer is able to inline the call which results in a better performance. However, those are just assumptions of mine. If anyone could clarify this, I'd appreciate it! :)

这篇关于当它不是静态的时,如何使用现有方法代替lambda?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆