5

I have a little simple question.

Let's say I have a data object with about 10 properties, and I want to pass data from my object to a function. Most of the time I only need one of these values in the receiving function, and could just as well pass only that value (let's say an int). So what is the pros and cons with always sending the whole object vs only sending one of the contained values?

Is there a best practice?

svick
  • 236,525
  • 50
  • 385
  • 514
Markus
  • 3,297
  • 4
  • 31
  • 52

6 Answers6

13

From a performance perspective, it's no problem to pass a whole object. In C# you only pass a reference to an object so there is no copying.

But compare the following two methods from a Unit Testing perspective:

decimal CalculatePrice(Customer customer);

or

decimal CalculatePrice(decimal productPrice, int numberOfItems);

The second one is much easier to understand and to test. This principle is called the Law Of Demeter.

The Law Of Demeter states that an object should only know about the things it really needs. So passing a complete Customer object only to access the Order property on it violates the Law Of Demeter.

Wouter de Kort
  • 39,090
  • 12
  • 84
  • 103
  • Well if you're keeping productPrice and numberOfItems inside a "Customer" object, then I think that's a bit messed up. Better (IMHO) would be an Order object with a Order.CalculatePrice method. – Matt Burland Mar 13 '12 at 12:56
  • Yep :) the example is exaggerated. That's why I say passing a complete Customer to access the Order (to access price and number of items). – Wouter de Kort Mar 13 '12 at 12:59
  • This is double-edged, though; see my reply to Robaticus on my answer – Marc Gravell Mar 13 '12 at 13:01
  • @MarcGravell Wouldn't you then pass a Region object, a price and a number of items? Or you would start using Strategy objects? But my point remains, a method should ask for what it really needs. Otherwise you have a lying API ;) It's really hard to mock a method which takes a top level object only to get access to some low level object. – Wouter de Kort Mar 13 '12 at 13:06
  • @Wouter however you architect it (strategy, whatever) - if the abstract API cannot possibly predict the exact *fields* that matter, then at *some* point your code is going to need to call some method somewhere with a higher level of abstraction, i.e. the object – Marc Gravell Mar 13 '12 at 13:10
11

When you "pass an object", you are actually just passing the reference to the object - so 4 bytes on x86 and 8 bytes on x64. So if the method feels natural to take the object, just pass the object; that's fine. Any other approach is probably going to be worse.

Of course, if it feels "natural" that the method only needs a single int, and could only ever need the single int, then passing an int is fine too.

My point is: write the method to support what makes sense for the method.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    Sorry, Marc, but I can't disagree more with this response. Doing this when your method doesn't require all of the other data makes code less maintainable and less unit testable. – Robaticus Mar 13 '12 at 12:56
  • You're right to emphasize the **natural** feel of the method. Performance considerations in this scenario won't be relevant except in the most extreme of cases. – Falanwe Mar 13 '12 at 12:57
  • 2
    @Robaticus swings and roundabouts; you are also then *defining* the logic in terms of the API; if that was, say, an abstract/interface pattern, the base implementation **may not know** what is relevant. Taking Wouter's example: the price may, for some implementations, depend on the customer's region, for example. – Marc Gravell Mar 13 '12 at 13:01
  • @Marc - I agree that it is a fine line to walk between Single Responsibility and Dependency Inversion, but I've seen junior developers do this because they're lazy versus doing it for the right reasons. As in all things, I would recommend moderation and consideration for the appropriate implementation, versus a golden hammer in search of a penny-nail. Your point at the end sums it up well. Thanks! – Robaticus Mar 13 '12 at 13:23
  • @Robaticus yes, it is a tricky one - if only "start with common sense, then add some knowledge of the system/problem" worked as guidance; unfortunately, it often does not – Marc Gravell Mar 13 '12 at 13:24
4

A method is a purpose-built routine whose existence is to perform one operation. Therefore, it should take in parameters that provide no more and no less than what it needs to do what it was built to do. If it does not operate on an object, but instead a specific set of values, then it should take in those values as parameters. If it operates on the object as a whole, then it should take in the object.

moribvndvs
  • 42,191
  • 11
  • 135
  • 149
1

Both will serve the different use cases.

Are you thinking that if you pass an object the whole object will be copied? If yes, no the object is not copied; it is only value of the reference that is copied.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • No, that's not called pass by reference. The reference is being passed by value, which is different. Please read http://pobox.com/~skeet/csharp/parameters.html – Jon Skeet Mar 13 '12 at 12:53
  • That is only true if the object passed is a class, if it is a struct (e.g. an int as per the example in the question) it will be passed by its value. That won't be a problem if the OP is only using the value in a calculation, however if he wants to update it then it will need to be passed using the ref keyword. – Trevor Pilley Mar 13 '12 at 12:58
1

When passing an object to a function you are only passing a reference to that object, so it's not like it's a heavy operation. The only thing that gets copied is a pointer. If you pass an int, it'll be passed by value which means you will make a copy of the int.

The biggest difference to remember is that when you pass by reference, changes made to the object you pass in will be permanent changes to object. If you pass by value, because you make a copy, any changes to that parameter will be lost.

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
1

When you send an object in c#, if it is a reference type, you only pass the reference. However, if it is a value type, (int for instance) the value will be copied.

So if you want to modify an int contained in a object, sending only the int will result in the int contained in the object not being modified.

Consider this

public class A
{
    private int foo = 1;

     private void DoStuff()
     {
     staticMethod(foo);
     }
 }

 public static  void staticMethod(int value)
 {
      value += 1;
 }

At the end, foo will still be worth 1, and not 2.

squelos
  • 1,189
  • 6
  • 16