【问题标题】:Do value-type extension methods provide write-access to the original value?值类型扩展方法是否提供对原始值的写访问?
【发布时间】:2015-11-24 20:14:22
【问题描述】:

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

【问题讨论】:

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


【解决方案1】:

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

他们不是。

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

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

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

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

它只是原始值的副本吗?

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

您也不会在 .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();

完全避免这个问题。

【讨论】:

  • 一个值得 Jon Skeet 的答案❗️
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 2021-04-30
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 2011-08-09
  • 2016-11-21
相关资源
最近更新 更多