问题
To my knowledge this
in a extension method is passed as a ref
variable. I can verify this by doing
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();
My List<int> ints
is now 1, 2, 3, 4, 5, 0
.
However when I do
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);
I would expect my List<int> ints
to be 3, 4, 5
but remains untouched. Am I missing something obvious?
回答1:
The this
extension method parameter is passed by value, not by reference. What this means is that upon entering the extension method, you have two variables pointing to the same memory address: the original ints
and the list
parameter. When you add an item to the list inside the extension method, it is reflected in ints
, because you modify an object referenced by both variables. When you reassign list
, a new list is created on the managed heap and the extension method's parameter points to this list. The ints
variable still points to the old list.
回答2:
Well, when you try to modify property of some class instance you don't even need ref
because you're modifying instance rather then reference to it.
In this example you don't need ref
keyword as you modify property :
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);
}
Output : 10
And here you do need ref
keyword because you work with reference and not with instance :
...
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);
}
Output: 0
It's same for your scenario, extension methods are the same as normal static methods and if you create new object inside method then either you use ref
keyword (it's not possible for extension methods though) or return this object otherwise the reference to it will be lost.
So in your second case you should use :
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 + " ");
Output : 3, 4, 5
来源:https://stackoverflow.com/questions/33056956/extension-method-and-local-this-variable