C#扩展方法 - 返回调用对象

10

我刚接触扩展方法并探索它们的功能。

在不进行特定赋值的情况下,是否可能将调用对象分配给输出?

这里有一个简单的例子来解释:

public static string ExtensionTest(this string input)
{
    return input + " Extended!";
}

In the following examples ...

var foo = "Hello World!";

var foo2 = foo.ExtensionTest(); // foo2 = "Hello World! Extended!"

foo.ExtensionTest(); // foo = "Hello World!"

foo = foo.ExtensionTest(); // foo = "Hello World! Extended!"

有没有办法让foo.ExtensionTest()返回"Hello World! Extended!",而不必明确指定foo = foo.ExtensionTest()


听起来你正在寻找一个this ref修饰符,用于静态方法,调用站点看起来像foo.Extension();。不幸的是,目前该语言没有这个功能。也许可以向语言设计者推荐一些东西? :) 就我个人而言,我不想要它。 - Ani
3
@Ani:哈哈,不!哦天啊,你能想象接下来会出现的滥用吗? string bar = foo; foo.DoSomething(); Console.WriteLine(ReferenceEquals(bar, foo)); ...(输出结果为 False,开发者:什么鬼?! - Dan Tao
3
@Dan Tao:完全正确。你所有的引用都属于静态方法。 - Ani
7个回答

14
不,但这不可行的原因与字符串的不可变性有关,与扩展方法无关。
如果您有一个类:
public class SomeClass
{
     public int Value {get; set;}
}

还有一个扩展方法:

public static void DoIt(this SomeClass someClass)
{
    someClass.Value++;
}

会产生以下影响:

var someClass = new SomeClass{ Value = 1 };
someClass.DoIt();

Console.WriteLine(someClass.Value); //prints "2"

实际上我想在XmlNodes和XmlDocuments上执行此操作——我认为这只是一个更普遍问题的简单(我认为!)的例子。 - Shevek

6

最接近这种情况的方法(虽然有点奇怪)是接受一个 out 参数,并将其用作返回值:

public static void ExtensionTest(this string input, out string output)
{
    output = input + " Extended!";
}

例子:

string foo = "Hello World!";
foo.ExtensionTest(out foo);

有趣的是,虽然这更接近于你所询问的内容,但实际上打字稍微有点多。

需要明确的是:我不建议这样做,除非对你来说进行这种方法调用真的非常重要。另一个开发人员看到后大概率会惊呼“WTF?”。


我喜欢这个!根据发布的问题,这是一个很好的解决方法。干得好 +1 - VoodooChild

5
您看到的是由于字符串不可变性导致的。
无论如何,如果您想要更改对象,您都必须进行某种形式的赋值。

我实际上想在XmlNodes和XmlDocuments上执行此操作 - 这只是一个更简单的(我认为!)示例,用于一般问题。 - Shevek

4

'this'参数是按值传递的,而不是按引用传递。因此,你不能修改在扩展方法中别名为'this'的调用程序中的变量。


1

在.NET中,字符串是不可变的。所有公共的字符串方法也会返回一个新的字符串实例。


1

在扩展方法内部为变量分配新值,您需要在参数上使用 ref 修饰符,但 C# 编译器不允许在扩展方法上使用它(而且这也是一个不好的想法)。最好明确表明您正在更改变量。


0

对于可变字符串使用更快的 StringBuilder,并像指出的那样使用 refout 关键字。 StringBuilder 基本上是针对字符串的改进链表。
不可变字符串是一种设计决策,以实现与 C 语言和许多其他语言的紧密行为。

string str = "foo";

str  += "bar"; // str will be free for garbage collection, 
//creating a new string object.
//Note: not entirely true in later C# versions.

StringBuilder sb = new StringBuild();
sb.Append("foo");
sb.Append("bar"); // appends object references to a linked list.

另请参阅:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接