传递什么?引用对象还是值类型?

10

各位,我有一个“最佳实践问题”。例如我有以下这些类:

class Person
{
   public int age {get; set;}
}

class Computer
{
   public void checkAge(Person p)  // Which one is recommended   THIS
   {
       // Do smthg with the AGE
   }

   public void checkAge(int p)     // OR THIS
   {
       //Do smthg with the age.
   }
}

应该传递什么是推荐的?只需要我需要的(int数值类型)还是整个对象(引用类型)。

我问这个问题是因为我正在使用LINQ制作一个应用程序,并且我已经创建了许多实体,在这些实体中,我应该传递ID(外键),但我正在传递对象。

最佳方法是什么?


1
+1 我一直对此感到困惑,现在终于清楚了,谢谢。 - Srinivas Reddy Thatiparthy
这是我总是有疑问的类型问题。我需要问一下:D - MRFerocius
6个回答

16

checkAge函数应该只接受执行其工作所需的最小信息量。添加其他内容只会创建人为依赖关系。如果只需要一个int,那么这就是我应该采取的解决方案。


太好了,Jared。所以我应该记住只提供必要的最小信息。有时候我需要传递2个整数,那么我应该给函数提供2个整数,以此类推,对吗? - MRFerocius
@MRFerocious,我会创建两个函数。一个版本只需要1个int,另一个版本接受2个int并具有明显不同的行为。 - JaredPar
1
这个原则被称为迪米特法则:http://en.wikipedia.org/wiki/Law_of_Demeter - Mike Daniels

12

我认为在这种情况下,答案可能是两者都不是。"Age"可能会被拆分到自己的类中,或者如果该操作与"Person"上下文相关,则可能会被放置在"Person"类内部。


3
根据提供的信息,两个解决方案都不好。
第一个解决方案要求Computer类知道Person.Age,但没有明显的原因。
第二个解决方案将一个与Computer对象属性无关的方法附加到Computer类上。
如果这是一个验证操作,一些上下文会很有帮助。在这种情况下,CheckAge应该属于Person类(可能还有一个IsAgeAcceptable属性)。
为什么Computer要检查Person的年龄?答案决定了什么是有意义的...

@Steven A. Lowe - 我认为OP只是举了一个例子。我确信或者希望他在Computer类中并没有真正拥有一个checkAge函数。 - JonH
哈哈哈,伙计们,当然这只是一个例子。我问这个问题是因为我正在使用Linq并且需要传递一些ID,但在某些情况下我有3个,所以我决定传递对象。因此,我将选择仅传递整数。 - MRFerocius

2

遵循函数的迪米特法则。该法则基本上规定实体应松散耦合。请问自己一个问题,计算机对象是否应知道人员对象?在这种情况下,也许你在checkAge内部所做的一切只是检查一个int值。如果是这种情况,那么你觉得传递整个对象是必要的吗?在这种情况下,只需传递人员年龄,并将其作为int接收即可。

因此,请优先考虑:

public void checkAge(int n)

0
我想指出,int Age 可能不是存储该值的最佳方式。 (为什么 DateTime 是属性而不是方法)
class Person : IBorn
{
  public DateTime Birth {get; set;}
}

interface IBorn
{
  DateTime Birth {get; set;} 
}

interface IDateTimeFactory
{
  DateTime Now();     
}

class DefaultDateTimeFactory : IDateTimeFactory
{
  public DateTime Now()
  {
    return DateTime.Now;
  }
}

public static class IBornExtensions
{
  public TimeSpan AgeFromNow(this IBorn birthed, IDateTimeFactory dtf)
  {
    return dtf.Now() - birthed.Birth;
  }
  public TimeSpan AgeFrom(this IBorn birthed, DateTime from)
  {
    return from - birthed.Birth;
  }
}

class Computer
{
  public void checkAge(IBorn birthed)        
  {
    var age = birthed.Age((new DefaultDateTimeFactory()).Now());
  }
}

我相信有人会想,"这个答案的代码好像太多了,看起来有些过分"。但是就像 DateTime.Now 应该是一个方法(因为方法返回值可能会因每次调用而改变,而属性通常不应该在每次 调用 时更改值,参见上面的链接),年龄会随着每次调用而改变,所以属性应该改为出生日期。接下来,我将确定年龄的方法封装为扩展方法,因为任何可以 IBorn 的东西肯定都有一个年龄(忽略哲学问题,如果某物已死亡,它是否还有年龄 :P)。最后,创建了 IDateTimeFactory 对象,以便可以对 Age 方法进行单元测试,以确定它是否正确计算年龄(否则,硬编码 DateTime.Now 意味着您无法告诉某物与其他物品相比有多老,例如我的兄弟和姐姐)。


0
我想指出的是,当传递引用时,引用是一个32位整数,而数据类型则是复制。因此,如果您的值类型大于32位int,则在性能或内存方面存在任何问题时,请通过引用传递。

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