17

How can I pass an object of a "MyClass" (C#) by Parameter-by-Value to a method? example:

MyClass obj = new MyClass();
MyClass.DontModify(obj); //Only use it!
Console.Writeline(obj.SomeIntProperty);

...

public static void DontModify(MyClass a)
{
    a.SomeIntProperty+= 100;// Do something more meaningful here
    return;
}
ViV
  • 1,998
  • 8
  • 27
  • 54
  • 9
    People may tell you to use a `struct`. Don't. – SLaks Jun 21 '12 at 16:05
  • 1
    download: (CloneExtensions ) from nuget. It will extend c# object with GetClone() method that accept flags where you can use to indicate you want a shallow copy. https://www.nuget.org/packages/CloneExtensions/1.2.0 – alsafoo Jan 29 '15 at 19:00

6 Answers6

17

By default object types are passed by value in C#. But when you pass a object reference to a method, modifications in the object are persisted. If you want your object to be inmutable, you need to clone it.

In oder to do it, implement the ICloneable interface in your class. Here is a mock example of how to use ICloneable:

public class MyClass : ICloneable
{
  private int myValue;

  public MyClass(int val)
  {
     myValue = val;
  }

  public void object Clone()
  {
     return new MyClass(myValue);
  }
}
Daniel Peñalba
  • 30,507
  • 32
  • 137
  • 219
  • 6
    Unfortunately IClonable doesn't define whether its a deep or shallow copy. You might end up (when using classes you didn't write yourself) still copying references somewhere down the line. And as it predates Generics, ICloneable returns an object, so you need to cast ... the whole thing is rather ugly. – linac Jun 21 '12 at 16:15
  • 3
    You can simply write `return MemberwiseClone();` in the `Clone` method. – Olivier Jacot-Descombes Jun 21 '12 at 16:17
  • 1
    I assume that the class that the user need to clone is a sellf-written class by reading the sample code. In this case you can control the clone by creating a new object. Of course you need to clone embedded types if needed. – Daniel Peñalba Jun 21 '12 at 16:17
  • 2
    @linac: You can write a typed `Clone` method and not implement `IClonable`. You can even name it `ShallowClone` or `DeepClone` to make things clear. But I agree that this does not eliminate the deep cloning problematic. – Olivier Jacot-Descombes Jun 21 '12 at 16:18
  • 5
    @OlivierJacot-Descombes: [From msdn](http://msdn.microsoft.com/de-de/library/system.object.memberwiseclone.aspx): _The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. **If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object**._ (edit: your second comment came after I started mine…) – linac Jun 21 '12 at 16:20
  • 1
    For maintanability, I always prefer to write my own `Clone()` method, but this depends on your criteria. – Daniel Peñalba Jun 21 '12 at 16:22
  • 1
    @linac: Yes, `MemberwiseClone` returns a shallow clone. This will protect value members and immutable reference values als well and the references of nested objects but not the members of these nested objects. – Olivier Jacot-Descombes Jun 21 '12 at 16:31
8

By default, it is passed by value. However, you're passing the object reference by value, which means you can still edit values within the object.

In order to prevent the object from being able to change at all, you would need to actually clone the object prior to passing it into your method. This would require you to implement some method of creating a new instance that is a copy of your original object, and then passing in the copy.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
6
public static void DontModify(MyClass a)
{
    MyClass clone = (MyClass)a.Clone();
    clone.SomeIntProperty+= 100;// Do something more meaningful here
    return;
}
MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
4

You could create a Clone method on your object to pass the return value to your method. C# cannot pass reference types by value so this might be a good alternative.

public MyClass CreateClone()
{
    return new MyClass() { SomeIntProperty = this.SomeIntProperty };
}
Dan Lister
  • 2,543
  • 1
  • 21
  • 36
0
class Program
{
    static void Main(string[] args)
    {
        Person p1 = new Person()
        {
            Name = "Alsafoo",
            Address = new Address()
            {
                City = "Chicago"
            }
        };

        Person p2 = new Person(p1.Address);
        p2 = p1.GetClone(CloningFlags.Shallow);
        p2.Name = "Ahmed";
        p2.Address = new Address(){City = "Las Vegas"};
        Console.WriteLine("p1 first name: {1} --- p1 city: {2} {0}p2 first name: {3} ---- p2 city: {4}", 
            Environment.NewLine, p1.Name, p1.Address.City, p2.Name, p2.Address.City);
        Console.ReadKey();
    }
}
public class Person
{
    public Person()
    {}
    public Person(Address a)
    {
        Address = a;
    }
    public string Name { get; set; }
    public Address Address { get; set; }        
}

public class Address
{
    public string City { get; set; }
}

Download this extension https://www.nuget.org/packages/CloneExtensions/1.2.0

alsafoo
  • 778
  • 4
  • 18
  • 2
    "Download this" is not an appropriate answer to a programming question. Also, any magic cloning utility is going to be many times slower than making your own `Clone` Method, because those utilities would have to use Reflection or JSON or something in order to understand the objects they are cloning. – Suamere Jun 19 '18 at 13:54
  • 2
    You don't have to be childish because somebody downvoted, especially since I actually provided feedback. Notice how Daniel actually answered the question, and THEN provided an **alternative** option. You can't claim you provided an alternative, because "alternative" means you have established a foundation. You basically just advertised some random package and gave an example how to use it. Given the choice between explicit control of the objects in a domain vs Reflection, Reflection is objectively slower. How much you're willing to swallow is up to your circumstance and should be measured. – Suamere Jun 19 '18 at 17:52
0

Created a Extention method

using System.Text.Json;    

namespace Student.Utilities 
{
    public static class CloneExtension
    {
        public static T Clone<T>(this T cloneable) where T : new()
        {
            var toJson = JsonSerializer.Serialize(cloneable);
            return JsonSerializer.Deserialize<T>(toJson);
        }
    }
}

Now, while calling, call it like this to pass the clone to another method:

public void CreateStudent(Student student) 
{
      Student clonedStudent = student.Clone<Student>();
      _repository.CreateStudent(clonedStudent);
}
KushalSeth
  • 3,265
  • 1
  • 26
  • 29