【问题标题】:method returning same object which was passed as parameter返回作为参数传递的相同对象的方法
【发布时间】:2013-03-24 18:50:12
【问题描述】:

将一个对象传递给一个方法,然后返回相同的对象而不是在方法本身内部创建一个新对象,这是可以接受的做法吗?

例如:如果有一个实体类如下:

class UserDetails {
    int UserID { get; set; }
    string UserName { get; set; }
    string UserAge { get; set; }
}

然后我将这个类的一个实例传递给一个方法,如下:

UserDetails UserInfo = new UserDetails();
UserInfo = Get_Details(UserInfo);

该方法做以下是否合理?

public UserDetails Get_Details(UserDetails user) {
    // SQL Operations...
    user.age = 32;
    return user;
}

【问题讨论】:

  • 观察,您是在设置细节而不是获取它们:-p
  • 一件小事:您的函数名称具有误导性(我不会猜测名为 Get_Details 的函数会更改其输入)。除了你说明的做法是正确的。
  • 也许这应该在代码审查堆栈交换上?
  • 我相信这就是所谓的草/鹅模式。

标签: c# oop methods


【解决方案1】:

IMO,无需返回对象。由于它是通过通过引用传递给方法的,因此调用者已经拥有对同一对象的引用(在方法完成后具有更新的值)。

另一方面,在某些情况下有用的是流式接口,其中类的实例方法再次返回实例,例如:

class X
{
  public X DoThis(int number)
  {
    // do something
    return this;
  }
  public X DoThat(string name)
  {
    // do something else
    return this;
  }
}

这允许编写非常易读的代码,例如:

var x = new X().DoThis(23).DoThat("asdf");

【讨论】:

    【解决方案2】:

    这对builder pattern 很有用(当您想逐步构建复杂对象时)。

    作为一个非常糟糕的例子:

    class FooBuilder {
      FooBuilder WithAge(int age);
      FooBuilder WithUrl(Url url);
    
      Foo ToFoo();
    }
    
    new FooBuilder().WithAge(12).WithUrl(new Url("http://www.happybirthday.com/").ToFoo();
    

    在您的特定情况下,我更喜欢使用初始化程序语法一次性初始化所有内容。

    new User { Age = 45, UserName = "Bob", Id = 101 };
    

    【讨论】:

      【解决方案3】:

      这并没有什么可怕的错误,只是一些观察;

      • 您正在一个名为 get 的方法中设置详细信息,也许 load 更合适。
      • 如果你只传入UserDetails,因为你想要你的id,那么参数应该只是id。这样可以保持界面的连贯性。
      • 在方法中修改参数对象通常被认为是不好的形式,即变异原则。

      【讨论】:

        【解决方案4】:

        这是一种可能的方法,当您只有一个项目可以工作时,也是最好的。您也可以考虑使用ref,它会创建对传递参数的引用

        public void Get_Details(ref UserDetails user)
        {
            // SQL Operations. . .
            user.age= 32;
        }
        

        这样,您不会传递副本,而是引用您传入的对象。但这可能会变得非常模糊并且在您的情况下是不必要的。请参阅here 了解详情。

        【讨论】:

        • 如果您想更改实际引用,您只能使用ref 关键字。不带 ref 关键字传递它不会创建对象的副本,它只会创建引用的副本。
        • 这没有意义……那为什么会有ref呢?
        • ref 关键字创建对持有该引用的变量的引用(如果它是值类型,则创建持有该值的变量)。您可以更改从方法内部传入的变量。
        • 我们现在是在谈论对象还是变量?
        • @bash.d 对于 Guffa 描述的情况。那就是user = new UserDetails() 的语义取决于user 参数是用还是不用ref 声明的。如果它是用ref 声明的,那么赋值在方法之外是可见的(即,用作参数的变量现在指向与调用方法时不同的对象)。不使用 ref 方法外的变量仍然指向同一个对象
        【解决方案5】:

        那样做是毫无意义的,因为你所做的任务不会改变任何事情。

        这样称呼它:

        UserInfo = Get_Details(UserInfo);
        

        给出与调用它相同的结果并忽略返回值:

        Get_Details(UserInfo);
        

        返回引用可能只会让人感到困惑,导致人们相信该方法返回了一个新实例,因为这是返回引用的唯一合乎逻辑的原因。

        在类中使用该方法会更有意义,因此您将其称为:

        UserInfo.Get_Details();
        

        如果您的方法应该初始化对象,您宁愿将代码放在构造函数中,也不愿在创建实例后调用它:

        class UserDetails {
        
          int UserID { get; set; }
          string UserName { get; set; }
          string UserAge { get; set; }
        
          public UserDetails() {
            Get_Details(this);
          }
        
        }
        

        然后你只需创建实例,构造函数加载数据:

        UserDetails UserInfo = new UserDetails();
        

        【讨论】:

          【解决方案6】:

          您可以在实体的构造方法或实体类中的其他方法中填充实体。创建后即可使用。

          public class SomeClass
          {
              public string Field_1;
              public int Field_2;
          
              public SomeClass(int ID)
              {
                  // Sql operations by ID or another value
                  // set fields
              }
          
              public AnotherMethod(int ID)
              {
                  // Sql operations by ID or another value
                  // set fields
              }
          }
          

          【讨论】:

            【解决方案7】:

            您最好查看存储库模式和 OOD 的概念。一般来说,我更喜欢投影或完全加载的实体。

            public UserDetailsProjection GetDetailsByUserId(Guid userID)
            {
               // Code goes here
               return user;
            }
            

            注意:ref 不是必需的,因为所有对象都是通过引用传递的。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-08-02
              • 2023-03-27
              • 2014-11-27
              • 1970-01-01
              • 1970-01-01
              • 2020-06-05
              • 1970-01-01
              • 2013-11-29
              相关资源
              最近更新 更多