matt
matt

Reputation: 4244

Copy constructor on C# struct, that works like a C++ copy constructor

Is it possible to have a copy constructor on a C# struct, that works like a C++ copy constructor? Because mine isn't working.

Specifically, it's not being called automatically during an assignment, as would happen with a C++ copy constructor.

struct TestStruct
{
    public TestStruct(TestStruct other)
    {
        // this function is never called
    }
}

public void Afunction()
{
    TestStruct A = new TestStruct();
    TestStruct B = new TestStruct();

    A = B; // in c++ copy constructor would be called here
}

Upvotes: 6

Views: 2309

Answers (3)

Mahdi Tahsildari
Mahdi Tahsildari

Reputation: 13592

It is because you are not calling your parameterized-constructor. Take a look at the code below:

struct TestStruct
{
    public string WhoIsCalled;
    public TestStruct(TestStruct other)
    {
        // this function is never called
        WhoIsCalled = "Constructor with argument";
    }

}

public string Afunction()
{

    TestStruct A = new TestStruct();
    return A.WhoIsCalled;

}
public string Bfunction()
{

    TestStruct B = new TestStruct(new TestStruct());
    return B.WhoIsCalled;

}

When you run Afunction, it returns null. It means that your code is using the default-parameterless-constructor. But in Bfunction, your code is providing the parameter, so your constructor is called hence the WhoIsCalled string gets value.

Upvotes: 8

Tanveer Badar
Tanveer Badar

Reputation: 5512

The reason why C# does not have copy constructors while C++ does has to do with the semantics either language follows when calling functions/methods.

C++, inheriting its C background, prefers value (or copy) semantics when passing arguments to a function.

C#, running on top of a garbage collected environment - among other reasons - passes its parameters as references.

A function (or method in C#) which looks identical syntax wise

void f(string s) { /* does something with s here */ }

has very different semantics for how it is invoked. C++ would make a copy of whatever object was being passed in f(abc) which C# would simply pass the reference it had in abc to f() and make s point to the same object. Think of f() being written in C++ as

void f(string& s) { /* does something with s here */ }

A similar reasoning applies to a = b; meaning copy assignment in C++ while copying reference in C#. Also why you cannot overload = in C#.

P.S.: Nitpickers will not be entertained.

P.P.S. : Value types actually have value semantics, but still you cannot overload operator =() for them.

Upvotes: 4

Rufus L
Rufus L

Reputation: 37060

Since others have already answered the question about how to call the "copy constructor" (which would be to pass the other instance to the constructor: TestStruct B = new TestStruct(A);), I'll try to answer the other questions.

"Can you have a copy constructor for a C# struct, that works like a C++ copy constructor?"

No. In C++ a copy constructor is automatically called during an assignment of a type to another instance of that type. In C#, a shallow copy of the object is made, meaning that the value of value-type members is copied, and the reference of reference-type members is copied.

From the comments: "Can you overload the assignment operator?"

No. The assignment operator is not something that can be redefined. The default behavior for the language is what happens every time. Of course you can write your own method that returns a new instance of a type based on the property values of another instance, but that method must be called explicitly, and cannot be defined such that it's called during an assignement.

Also from the comments: "I am trying to transparently replace a native value type (int) with a struct or class"

Well now here it sounds like you might have something to work with. Although I'm really not sure what you mean by "replace a native value type", c# does allow you to write your own user-defined conversion operators which allow implicit (and explicit) conversions between two types. This effectively overrides the assignment operator when you're assigning from a different type.

Granted, this is not what your example is doing, but based on your comment it may be useful.

For example, if you wanted to create in instance of your struct from an int, you can do:

struct MyIntReplacement
{
    public int MyValue { get; set; }

    public static implicit operator MyIntReplacement(int value)
    {
        return new MyIntReplacement { MyValue = value };
    }
}

And now you can do something like:

int someValue = 5;
MyIntReplacement foo = someValue;

Upvotes: 2

Related Questions