StringBuilder扩展追加调用解析

本文关键字:调用 追加 扩展 StringBuilder | 更新日期: 2023-09-27 18:04:02

我有一个扩展方法,将IEnumerable中的每个对象附加到StringBuilder中。它用类型参数对IEnumerable进行操作,所以我的问题是它会触发Append()调用唯一的单独类型,还是会所有作为"对象"传递并且效率低下?如果我需要的话,我会针对特殊情况扩展函数,其中StringBuilder具有对类型唯一的Append()调用,但我需要知道我是否必须这样做。

    /// <summary>
    /// Appends each object in the enumerable to the StringBuilder's content.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sb"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentOutOfRangeException"/>
    public static StringBuilder AppendEach<T>(this StringBuilder sb, IEnumerable<T> e)
    {
        e.Do<T>(t => sb.Append(t));
        return sb;
    }
    /// <summary>
    /// Allows you to run code on each value in a collection in-line.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t"></param>
    /// <param name="action"></param>
    public static void Do<T>(this IEnumerable<T> e, Action<T> action)
    {
        foreach (T t in e) action(t);
    }

不确定我使用的Do扩展是否会改变问题的结果,所以我包含了它而不是简化代码。我知道有些人会因为我在这里写"有副作用的LINQ方法"而绞死我,但这与手头的问题无关。

StringBuilder扩展追加调用解析

不,如果你的意思是"它会触发Append()调用唯一的单独的类型",它将调用Append(Object)

因为碰巧有争议。c#编译器必须在编译时决定使用哪个方法。这意味着所选择的方法参数不能与您放入Append(…)中的变量冲突。由于编译器在编译时不知道T是什么,它将选择Append(object),因为无论T是什么,它都是唯一可以工作的。

我已经模拟了这个场景:

public class C
{
public static void Show(object value)
{
    "object".Dump();
}
public static void Show(int value)
{
    "int".Dump();
}
public static void Show(string value)
{
    "string".Dump();
}
}
public class MyClass<T>
{
   public void Append(T value)
   {
C.Show(value);
   }
}
public void Main()
{
var c1 = new MyClass<int>();
var c2 = new MyClass<string>();
var c3 = new MyClass<object>();
c1.Append(1);
c2.Append("1");
c3.Append(2);
}

显示了3次"object"

顺便说一句。如果从类中删除对象方法,它将无法编译,因为它将无法找到合适的方法。

把它留在这里供讨论,除非有人认为可以删除它——但是这里的信息是不正确的。

<引用类>

一切都不会作为"对象"传递——一切都将以T的形式传递(或者是stringbuilder调用Append()的最具体的T的超类)。如果你传入一个IEnumerable,那个enumerable中的每一项都会被传递给Append(object)覆盖,因为编译器不知道如何调用更具体的覆盖。然而,如果传入一个IEnumerable,则Append(string)将被调用,因为编译器现在对该类型有足够的了解,可以选择适当的覆盖。如果你传入一个IEnumerable,但是enumerable中的每个对象都是字符串,它仍然会调用Append(object)重写,因为类型信息丢失了。