2

I've been searching for a while on this because I'm naturally forgetful and I thought it would be nice to build something (an abstract class, interface, etc.?) that would force me to implement certain bits of code in a class I was writing.

In particular, I would like to force a new class to always have a constructor that takes a single parameter typed as itself in order to make duplication of the object easier. I've seen articles/questions elsewhere that talk about this, but I'm not sure this particular question has been asked (at least that I can find) or I'm simply not understanding enough of the other articles/questions to realize it. My apologies in advance.

I'm not interested in having a constructor in an abstract class, interface, etc. actually do anything. I'm merely interested in defining the requirement for a constructor signature in a derived class.

My ideal class would look like this:

public class GoodClass
{
    public GoodClass(GoodClass goodClass)
    {
        // copy components of goodClass to this instance
    }
}

So, I first began researching interfaces and also started reading up on abstract classes. I was thinking something like the code below would work, but alas I get errors. Is what I'm trying to do even possible? Is there any other way I could accomplish my goal without putting a sticky note on my monitor? :)

abstract class SelfConstructor
{
    abstract public SelfConstructor(SelfConstructor) { }
}

class NewClass : SelfConstructor
{
    //Required by SelfConstructor:
    public NewClass(NewClass newClass)
    {
        // copy components of newClass to this instance
    }
}

2 Answers 2

1

You could write a ReSharper plugin that recognises this case and highlights the class if it doesn't have a "copy constructor". This would be a daemon stage that would process the file as it's being edited, and add highlights. You can look through the abstract syntax tree of the file, look for all instances of IConstructorDeclaration, and then get the constructor's parameters from the ParameterDeclarations property. You can check that there is a constructor that only has one parameter, and that parameter is the same type as the class it's declared in.

You can compare the types by getting the constructor's parameter's TypeUsage and trying to downcast to IUserTypeUsage. You can then use ScalarTypeName.Reference.Resolve() to get an instance of IDeclaredElement. Compare this against the class's IClassDeclaration.DeclaredElement to see if they're the same instance.

Sign up to request clarification or add additional context in comments.

Comments

1

In C++, what you are talking about is a copy constructor, you actually get one by default!

C# doesn't have that concept (though of course you can define one); however, it is easier (and preferred) to simply implement ICloneable (MSDN), which requires you to implement the Clone method, that does the same thing.

Instead of:

object myObj = new CloneableObject(otherObj);

You write:

object myObj = otherObj.Clone();

The other thing you could do is force a constructor signature by not having a default:

public class BaseClass
{
    //No abstract constructors!
    public BaseClass(BaseClass copy)
    {
    }
}

Now when you derive, you have to use that overload in the constructor. Nothing will force the derived signature, but at least you have to explicitly use it:

public class DerivedClass : BaseClass
{
    public DerivedClass() : base(this)
    {
    }
}

The above example clearly shows that it doesn't "force" you to have a copy constructor, but like a sticky note, would serve as a good reminder.

I would definitely go the interface route, as that is what is there for (and you can use an abstract implementation!).

Note that you can take advantage of Object.MemberwiseClone if you want a shallow copy for free. All objects get this, no interface required.

6 Comments

A clone method is fine, but actually Microsoft advises against implementing ICloneable, mainly due to the fact that the interface doesn't state anywhere if the clone is deep or shallow.
@AdiLester Thats completely true, Clone can do whatever you want. If you follow the semantic though, its basically an interface for a copy operation.
... and here the quote from MSDN: "Because callers of Clone cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs."
You could of course, create IDeepCloneable or whatever you want to make the semantic clearer. If its just for me though, I'll stick with ICloneable.
Thanks for the advice, @BradleyDotNET. Is there any benefit to using ICloneable other than being forced to implement Clone()?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.