值类型扩展方法是否提供对原始值的写访问?
Do value-type extension methods provide write-access to the original value?
我正在为一些自定义小容量编码和解码算法编写值类型(例如 int
)的扩展方法。
可能还有其他不使用扩展方法的设计,但我担心这不是我最后一次遇到这个问题,所以我想知道扩展方法如何与这种类型一起工作设计。
例如:
int i = 10;
string str = i.Encode(); // Convert 10 to an unpredictable string such as "tZh0Ao"
i = 5; // Overwrite i with a new value.
i.Decode(str); // Decrypt the string to reassign the original value of 10
我不确定 this
参数如何用于值类型扩展方法。
它只是原始值的副本吗?
或者它是否像 ref
或 out
参数一样工作,保留对参数值所做的更改?
例如:
/* This method will decode a string,
and assign the decoded value to 'this' int. */
public static void Decode(this int value, string str)
{
int result;
/* ... perform work with str to produce decoded value ... */
value = result; // Assign the decoded value to 'this' int.
/* If 'value' is just a copy of the original int,
the assignment won't have any permanent effect. */
}
I'd like to know how extension methods are expected to work with this type of design.
他们不是。
C# 3.0 中引入了扩展方法,以允许 LINQ 为任何 IEnumerable<T>
或 IQueryable<T>
实例查找 .Select
和其他方法,而不需要这些接口的每个实现重新定义方法,并且不破坏已经实现 IEnumerable<T>
的大量现有代码。
允许此工作不需要允许 this ref
扩展方法。这并不意味着这样的扩展方法没有意义,或者它们没有用,只是在创建扩展方法时没有考虑到它们。
这与我们没有扩展属性的原因相同。允许扩展属性被认为是 WPF 附加属性 IIRC 的一部分,但尽管它们可能有意义,但最终证明它们对于预期目标是不必要的,因此被排除在 C# 语言之外。
如果 this ref
扩展方法有令人信服的理由,请向语言设计者提出。这就是添加任何新语言功能的方式。如果尚无令人信服的理由,修改编译器所需的额外工作通常是不修改语言的原因。
Is it just a copy of the original value?
是的。所有扩展方法调用都由编译器转换为等效的静态方法调用。 i.ExtensionMethod();
和 ExtensionClass.ExtensionMethod(i);
做同样的事情。如果后者不能修改i
(因为它没有声明为ref
),前者也不能。
您也不会在 .NET Framework 中找到许多可变实例方法。通常认为使实例方法 return 成为一个新值更好,让调用者担心是将其分配给现有实例还是新实例。假设 DateTime.AddDays
修改了调用它的实例(可以这样设计类型)。那么典型的程序员不会理解为什么
public void AddOneDay(DateTime[] array) {
for (int i = 0; i < array.Length; i++)
array[i].AddDays(1);
}
和
public void AddOneDay(List<DateTime> list) {
for (int i = 0; i < list.Count; i++)
list[i].AddDays(1);
}
行为完全不同。
相同的逻辑适用于您自己的实例方法:尽管该语言允许您为自定义值类型创建变异方法,但通常最好避免使用它们以防止用户混淆。
如果您的情况是个例外,如果在您的情况下事实证明变异方法可以带来更好的开发人员体验,那么请向语言开发人员介绍您的情况。
但我认为一般用户不会理解您的 i.Decode(str)
如果有效的话会做什么。一个更典型的设计是创建一个
public static int Decode(this string str)
扩展方法,并作为
使用
i = str.Decode();
完全避免这个问题。
我正在为一些自定义小容量编码和解码算法编写值类型(例如 int
)的扩展方法。
可能还有其他不使用扩展方法的设计,但我担心这不是我最后一次遇到这个问题,所以我想知道扩展方法如何与这种类型一起工作设计。
例如:
int i = 10;
string str = i.Encode(); // Convert 10 to an unpredictable string such as "tZh0Ao"
i = 5; // Overwrite i with a new value.
i.Decode(str); // Decrypt the string to reassign the original value of 10
我不确定 this
参数如何用于值类型扩展方法。
它只是原始值的副本吗?
或者它是否像 ref
或 out
参数一样工作,保留对参数值所做的更改?
例如:
/* This method will decode a string,
and assign the decoded value to 'this' int. */
public static void Decode(this int value, string str)
{
int result;
/* ... perform work with str to produce decoded value ... */
value = result; // Assign the decoded value to 'this' int.
/* If 'value' is just a copy of the original int,
the assignment won't have any permanent effect. */
}
I'd like to know how extension methods are expected to work with this type of design.
他们不是。
C# 3.0 中引入了扩展方法,以允许 LINQ 为任何 IEnumerable<T>
或 IQueryable<T>
实例查找 .Select
和其他方法,而不需要这些接口的每个实现重新定义方法,并且不破坏已经实现 IEnumerable<T>
的大量现有代码。
允许此工作不需要允许 this ref
扩展方法。这并不意味着这样的扩展方法没有意义,或者它们没有用,只是在创建扩展方法时没有考虑到它们。
这与我们没有扩展属性的原因相同。允许扩展属性被认为是 WPF 附加属性 IIRC 的一部分,但尽管它们可能有意义,但最终证明它们对于预期目标是不必要的,因此被排除在 C# 语言之外。
如果 this ref
扩展方法有令人信服的理由,请向语言设计者提出。这就是添加任何新语言功能的方式。如果尚无令人信服的理由,修改编译器所需的额外工作通常是不修改语言的原因。
Is it just a copy of the original value?
是的。所有扩展方法调用都由编译器转换为等效的静态方法调用。 i.ExtensionMethod();
和 ExtensionClass.ExtensionMethod(i);
做同样的事情。如果后者不能修改i
(因为它没有声明为ref
),前者也不能。
您也不会在 .NET Framework 中找到许多可变实例方法。通常认为使实例方法 return 成为一个新值更好,让调用者担心是将其分配给现有实例还是新实例。假设 DateTime.AddDays
修改了调用它的实例(可以这样设计类型)。那么典型的程序员不会理解为什么
public void AddOneDay(DateTime[] array) {
for (int i = 0; i < array.Length; i++)
array[i].AddDays(1);
}
和
public void AddOneDay(List<DateTime> list) {
for (int i = 0; i < list.Count; i++)
list[i].AddDays(1);
}
行为完全不同。
相同的逻辑适用于您自己的实例方法:尽管该语言允许您为自定义值类型创建变异方法,但通常最好避免使用它们以防止用户混淆。
如果您的情况是个例外,如果在您的情况下事实证明变异方法可以带来更好的开发人员体验,那么请向语言开发人员介绍您的情况。
但我认为一般用户不会理解您的 i.Decode(str)
如果有效的话会做什么。一个更典型的设计是创建一个
public static int Decode(this string str)
扩展方法,并作为
使用i = str.Decode();
完全避免这个问题。