值类型扩展方法是否提供对原始值的写访问?

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 参数如何用于值类型扩展方法。
它只是原始值的副本吗?
或者它是否像 refout 参数一样工作,保留对参数值所做的更改?

例如:

/* 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();

完全避免这个问题。