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

时间:2015-11-24 20:14:22

标签: c# .net pass-by-reference extension-methods value-type

我正在为一些自定义的小容量编码和解码算法编写值类型的扩展方法(例如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. */
}

1 个答案:

答案 0 :(得分:2)

  

我想知道扩展方法如何与这种类型的设计一起使用。

他们不是。

在C#3.0中引入了扩展方法,以允许LINQ为任何.SelectIEnumerable<T>实例查找IQueryable<T>和其他实例,而无需定义这些接口的每个实现这些方法是新的,并且不会破坏已经实现IEnumerable<T>的大量现有代码。

允许此功能不需要允许this ref扩展方法。这并不意味着这样的扩展方法没有意义,或者它们没有用,只是在创建扩展方法时不考虑它们。

这与我们没有扩展属性的原因相同。允许扩展属性被视为WPF附加属性IIRC的一部分,但尽管它们可能有意义,但最终证明它们对于预期目标是不必要的,因此被排除在C#语言之外。

如果this ref扩展方法有令人信服的理由,请向语言设计人员提出建议。这就是添加任何新语言功能的方式。如果还没有令人信服的理由,修改编译器所需的额外工作通常是不修改语言的原因。

  

它只是原始值的副本吗?

是。所有扩展方法调用都由编译器转换为等效的静态方法调用。 i.ExtensionMethod();ExtensionClass.ExtensionMethod(i);做同样的事情。如果后者无法修改i(因为它未被声明为ref),前者也不能。{/ p>

您也不会在.NET Framework中找到许多变异实例方法。通常认为使实例方法返回一个新值更好,并让调用者担心是将其分配给现有实例还是新实例。假设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();

完全避免这个问题。