简体   繁体   中英

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
}

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.

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#.

PS: Nitpickers will not be entertained.

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

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM