Hossy
Hossy

Reputation: 159

C#: Force constructor signature using abstract class?

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
    }
}

Upvotes: 2

Views: 631

Answers (2)

citizenmatt
citizenmatt

Reputation: 18583

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.

Upvotes: 1

BradleyDotNET
BradleyDotNET

Reputation: 61369

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.

Upvotes: 1

Related Questions