C# 扩展方法与局部';这';变量

C# 扩展方法与局部';这';变量,c#,extension-methods,local,ref,C#,Extension Methods,Local,Ref,据我所知,在扩展方法中,此作为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(); 我希望我的列表int是3,4,5,但保持不变。我是否遗漏了

据我所知,
在扩展方法中,此
作为
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();

我希望我的
列表int
3,4,5
,但保持不变。我是否遗漏了一些明显的内容?

此扩展方法参数是通过值传递的,而不是通过引用传递的。这意味着在输入扩展方法时,有两个变量指向相同的内存地址:原始
ints
list
参数。将项添加到扩展方法内的列表时,它会反映在
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 + " ");
公共静态列表方法(此列表,Func谓词)
{
return list.Where(谓词).ToList();
}
List ints=新列表(新的int[]{1,2,3,4,5});
ints=ints.Method(i=>i>2);
foreach(ints中的int项)控制台。Write(item+“”);

输出:
3,4,5

列表
不是通过引用传递的,它是通过值传递的引用。通过引用传递会使被调用方内部调用方法中的变量具有别名,从而允许您直接分配给它。“通过引用传递”和“传递引用”之间存在差异。对列表的引用是通过值传递的,这意味着您可以访问和修改列表,但您没有接触外部也引用列表的变量。
(new list()).Method()
compiles=>参数不必是变量=>与
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 + " ");