Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Bind constructor parameters to instance variables

Tags:

c#

constructor

Very common scenario: I have a class with multiple instance variables and a constructor that accepts multiple parameters. Can I somehow bind one to the other? Assigning all parameters to the instance variables is very verbose and is one of the situations that could be (and should be) covered by the convention-over-configuration principle. My example code looks like this:

public class myClass
{    
    private object param1;
    private object param2;
    private object param3;
    private object param4;

    public myClass(object param1, object param2, object param3, object param4)
    {
        this.param1 = param1;
        this.param2 = param2;
        this.param3 = param3;
        this.param4 = param4;
    }
}

Is there an easy way to get rid of this and let C# do its magic automatically?

like image 258
Jan Avatar asked Aug 28 '12 12:08

Jan


3 Answers

There's nothing within the C# language which covers this, no. While tools can generate code for you, they may not necessarily keep it up to date and you'll still end up with the code present and visible. You could potentially do this in some scenarios using reflection, e.g.:

public MyClass(object param1, object param2, object param3, object param4)
{
    Helpers.PopulateFromConstructor(this, param1, param2, param3, param4);
}

... where you'd need to specify the values in the same order as the parameters, and keep the names the same as the fields etc. You may also find there are problems when the fields are readonly.

Personally I'd just suck it up - use tools to generate the code if you want, but otherwise just live with it.

Note that you may want to do validation as you set the fields, particularly around nullity. So your constructor body may actually end up like this:

public myClass(object param1, object param2, object param3, object param4)
{
    this.param1 = Preconditions.CheckNotNull(param1);
    this.param2 = param2;
    this.param3 = Preconditions.CheckNotNull(param3);
    this.param4 = param4;
}

(For a suitable Preconditions class, of course. I've gratuitously nicked the idea from Guava in Java code, as I use that in day-to-day coding. This is the approach we use in Noda Time too.)

like image 55
Jon Skeet Avatar answered Nov 07 '22 04:11

Jon Skeet


"... could be (and should be) covered by the convention-over-configuration principle..."

"Convention over configuration" typically applies to an API or framework, such as MVC or Entity Framework, not to the language itself. An API is typically a focussed, reusable, and above-all simplifying abstraction of functionality. In this situation, dictating convention can help to drive structure without compromising functionality.

However, this is not true of the programming language. The language is broad, and low-level, and complex by comparison. It should restrict its user as little as possible without diluting the value of the language. Assuming such a broad "convention" would be very prescriptive. Beyond this, it would be dangerous of the compiler to assume that a parameter with a given name must always be assigned to a private field of similar name.

For one, your convention isn't the only commonly-used one. For exqample, one common coding styles suggests underscore-led private fields (_param1), which your convention would miss. The constructor might have further logic beyond just those assignments, in which case your convention is too simple: should the "convention-driven" code be executed before or after any other constructor logic?

Most importantly, how would such a convention be overridden? If, in the constructor, you were to consume param1 in some other way, do you still execute the convention? What if, in the constructor, I assign a different value to this.param1? Should your convention occur before or after the code that the user has added?

Even these brief questions - for which many people will have very different and equally valid answers - are enough to suggest that such a convention is not as obvious, nor easily defined, as it might seem.

like image 32
Dan Puzey Avatar answered Nov 07 '22 04:11

Dan Puzey


While there are many plugins that can do this kind of thing - it's worth noting that if you VS2010+'s native ability to generate constructors from a model call when a matching constructor does not exist, you can use a simple keyboard shortcut to do the work for you.

I.e. if I a stub class:

class MyClass{

}

And then in a method somewhere I write something like this:

object p1, p2, p3;
//...  (get values for p1-3)
var a = new MyClass(p1, p2, p3);

When such a constructor does not exist, a little helper button appears. If you click on that, or press ALT+SHIFT+F10 (by default) you get a menu, one of the options on which is to generate a stub constructor, which will then change the MyClass code as follows:

class MyClass
{
    private object p1;
    private object p2;
    private object p3;

    public MyClass(object p1, object p2, object p3)
    {
        // TODO: Complete member initialization
        this.p1 = p1;
        this.p2 = p2;
        this.p3 = p3;
    }

}
like image 23
Andras Zoltan Avatar answered Nov 07 '22 05:11

Andras Zoltan