扩展方法和局部'this'变量

本文关键字:this 变量 方法 扩展 局部 | 更新日期: 2023-09-27 18:17:16

据我所知,扩展方法中的this是作为ref变量传递的。我可以通过

来验证
public static void Method<T>(this List<T> list)
{
    list.Add(default(T));
}
List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 });
ints.Method();

我的List<int> ints现在是1, 2, 3, 4, 5, 0

但是当我这样做

public static void Method<T>(this List<T> list, Func<T, bool> predicate)
{
    list = list.Where(predicate).ToList();
}
List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 });
ints.Method(i => i > 2);

我希望我的List<int> ints3, 4, 5,但保持不变。我错过了什么明显的东西吗?

扩展方法和局部'this'变量

this扩展方法参数是按值传递的,而不是按引用传递的。这意味着在进入扩展方法时,有两个变量指向相同的内存地址:原始的intslist参数。当您向扩展方法中的列表中添加一个项目时,它会反映在ints中,因为您修改了两个变量引用的对象。当您重新分配list时,将在托管堆上创建一个新列表,并且扩展方法的参数指向该列表。ints变量仍然指向旧列表。

嗯,当你试图修改某些类实例的属性时,你甚至不需要ref,因为你是在修改实例而不是引用它。

在这个例子中,你不需要ref关键字来修改属性:

    class MyClass
    {            
        public int MyProperty { get; set; }
    }
    static void Method(MyClass instance)
    {
        instance.MyProperty = 10;                     
    }
    static void Main(string[] args)
    {
        MyClass instance = new MyClass();
        Method(instance);
        Console.WriteLine(instance.MyProperty);
    }

输出:10

这里你确实需要ref关键字,因为你使用的是引用而不是实例:

    ...
    static void Method(MyClass instance)
    {
        // instance variable holds reference to same object but it is different variable
        instance = new MyClass() { MyProperty = 10 };
    }
    static void Main(string[] args)
    {
        MyClass instance = new MyClass();
        Method(instance);
        Console.WriteLine(instance.MyProperty);
    }
输出:

0

对于您的场景来说是一样的,扩展方法与普通静态方法相同,如果您在方法内部创建新对象,那么您要么使用ref关键字(虽然扩展方法是不可能的),要么返回此对象,否则对它的引用将丢失。

所以在第二种情况下,你应该使用:

public static List<T> Method<T>(this List<T> list, Func<T, bool> predicate)
{
    return list.Where(predicate).ToList();
}
List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 });
ints = ints.Method(i => i > 2);
foreach(int item in ints) Console.Write(item + " ");

输出:3, 4, 5