在实例化时调用类方法?

8

我不知道如何更好地描述它,所以标题可能有点混淆。

我想知道是否可以通过使用... = new MyClass()来实例化一个类,并在实例化时立即调用该类的非静态方法?

例如像这样:

return new MyClass().SetName("some name");

我想我之前看到过类似的内容但是找不到了。 做这样的事情有点烦人...


(Note: The text has been translated into simplified Chinese)
MyClass myclass = new MyClass();
myclass.SetName("some name");
return myclass;

有没有办法缩短它或者像我的第一个例子那样做呢?(请不要建议我使用属性代替SetName(string) - 这只是个例子)
提前致谢!

4
如果你的例子不是一个好的例子——把Name改为属性似乎是完全合理的——那么你应该把你的例子改成一个好的例子。 - Jon Skeet
如上所述,使用属性。然后您可以使用参数调用构造函数,例如:new MyClass { Name = "myName" } - ub1k
如果这些方法应该总是被调用,它们应该在构造函数中。如果它们只应该通常(但不总是)被调用,你应该有两个构造函数(或一个带有参数的构造函数,定义要做什么)。如果它们通常不被调用,那么我认为你首先不会问这个问题。 - Matthew Watson
或者,您可以添加一个以名称为参数的构造函数 MyClass(String name),然后在那里设置名称变量(或属性)。 - David Hope
最后但并非不重要的是,为了调试目的,在单独的语句中设置断点更容易。 - millimoose
显示剩余2条评论
7个回答

21

如果您确实有一个属性,您可以使用对象初始化器:

return new MyClass { Name = "some name" };

如果您确实非常需要使用一种方法,那么唯一的选择就是使该方法再次返回该实例:

public Foo SomeMethod()
{
    // Do some work
    return this;
}

这是你可以编写的内容:

return new Foo().SomeMethod();

作为一种非常极端的做法,如果您无法更改所调用的方法,您可以编写扩展方法:

(原文)

public static T ExecuteAndReturn<T>(this T target, Action<T> action)
{
    action(target);
    return target;
}

然后你可以写:
return new Foo().ExecuteAndReturn(f => f.SomeMethod());

但那真的很糟糕。在这些情况下使用本地变量会更加简单...


奇怪的是,Jon Skeet竟然没有提到我提出的(看起来很简单和无害的)解决方案(构造函数参数),这让我觉得它有严重问题。这真是扭曲! - ppeterka
@ppeterka:我假设OP想要做一些无法通过构造函数参数完成的操作。但由于例子不好,很难知道具体情况。 - Jon Skeet
哦,好的。这解释了一切。我离开了边缘,消防员还没到,所以我想我可以逃脱责任... - ppeterka

7
如果 SetName 返回 this,那么你可以像第一个代码示例中所想要的那样执行操作。

2
抵制负评在这里非常困难。这是一个糟糕的解决方案,会混淆意图,违反搜索引擎结果页面(SERP)的规定。 - spender
1
如果你想在未来重新访问这样的代码,仅仅通过查看一个地方就无法确定正在发生什么。为了确定代码的意图,存在一层间接性,使人难以理解代码。至少对于原始的三行代码,意图是显而易见的。 - spender
我并没有试图为这样的设计辩护或反对。在我看来,流畅的接口往往比许多人想象的要不那么有用。我只是简单地回答了OP的问题,放弃了任何道德或伦理上的讨论。 - Jake H
确实...我想这更像是对楼主的陈述,而不是对你的。 - spender

7

这个问题存在一个巨大的误解:

...并在实例化过程中立即调用该类的非静态方法

例如像这样:

return new MyClass().SetName("some name");

事实上,调用SetName函数是在实例化完成后发生的。它并不是在“实例化时”发生。这与以下情况完全相同:
MyClass newInstance new MyClass();
return newInstance.setName("some name");

所以当调用SetName方法时,构造函数已经完成了它需要做的一切,对象已经准备好了。除此之外,从语法上讲是可行的,你只需要像其他人指出的那样返回this,并相应地指定返回类型。然而,我不会在setter中这样做...这不好看。另外,如果您总是需要设置名称,请考虑使用一个期望名称作为参数的构造函数,并在构造函数中设置它:
public class MyClass
{
    public String name;
    public MyClass(String initialName)
    {
        name = initialName;
    }
}

然后你可以使用一种非常简短的形式来使用它:
MyClass instance = new MyClass("someName");

6
很容易做到。通常这被称为“流畅接口”,但使用更合适的方法名称。
以下是如何编写SetName以实现此功能:
public MyClass SetName(...)
{
    ...
    return this;
}

这将允许您使用所需的语法。然后,您可以链接多个这样的调用,通常是针对不同的方法:
return new MyClass().SetName("kkk").SetAge(44).SetAddres("...");

然而,我建议您考虑添加一个更合适的结构来完成所有这些操作。

请注意,“流畅接口”通常不适用于此上下文。 流畅接口通常应用于不可变对象,而不是可变对象。 - Servy
具体来说,它们通常用于可变构建器对象上,这些对象被传递给不可变对象的构造函数。 - Matthew Watson

3
您可以像这样使方法可链接起来:
public void SetName(String name) {
    this._name = name;
    return this;
}

3

除非SetName的类型是它所在类的类型并返回this,否则你无法避免使用一个中间变量。当然,你可以采用流畅的语法,并使你的SetName返回该对象,但这不是C#的本地习惯用语。

class MyClass {
    public int A {get;private set;}
    public int B {get;private set;}
    public MyClass SetA(int a) {
        A = a;
        return this;
    }
    public MyClass SetB(int b) {
        B = b;
        return this;
    }
}

现在您可以这样做:
return new MyClass().SetA(123).SetB(456);

1
你可以创建一个静态属性,作为工厂返回一个新的实例。在这种情况下,调用看起来像这样:

MyClass.GetInstance.SetName("some name");

不确定这是否是您想要的。或者,为什么不从构造函数中调用该方法,并通过构造函数传递所需的参数。

或者,第三个选择是构建一个工厂类,处理所有这些额外步骤,并返回一个实例给您。


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