Question

I was just thinking,

if I need to write a constructor for let's say an Apartment class, and the apartment class has several of properties such as ApartmentSize, NumberOfBedrooms, NumberOfShowers, CurrentMarketValue, PurchasePrice etc.

Will it be more readable to create a struct that is called, let's say, ApartmentProperties and to have all of the above properties as members of this struct, so when I need to construct an apartment, all the constructor requires is just this struct?

If not, what would be a more elegant way of doing it?

Was it helpful?

Solution

Seems a bit circular. You've got an object whose constructor needs all these values, so you're creating an object to contain them. So now you've got a struct that needs all these values... how do you create the struct?

You're proposing this:

ApartmentProperties props = new ApartmentProperties(size, numBedrooms, numShowers, marketValue, purchasePrice);
Apartment apt = new Apartment(props);

It seems no different to doing this:

Apartment apt = new Apartment(size, numBedrooms, numShowers, marketValue, purchasePrice);

If this is the only time you're using the ApartmentProperties struct, and all you're doing is putting all these values into it, passing it to a constructor, and then pulling them out again, then it feels unnecessary. It's just one more object to think about.

In the comments it's been suggested that if you don't like having so many parameters on the constructor, then you could do this:

Apartment apt = new Apartment();
apt.Size = size;
apt.NumBedrooms = numBedrooms;
apt.Numshowers = numShowers;
apt.MarketValue = marketValue;
apt.PurchasePrice = purchasePrice;

I'm not a huge fan of this approach. Now your constructor is smaller and tidier, yes, but all you've done is move the logic that was neatly wrapped up inside it out to wherever you're calling it from. This makes the calling code responsible for making sure that all the properties are properly assigned. I'd advise leaving the assignments in the constructor - it just lets you assume that an Apartment object has its properties assigned because you know the constructor will have done it.

Of course, there is a middle ground. You could take out some of the constructor parameters, leaving only those that must be there. For example, an apartment always has a size, a number of bedrooms, and a number of showers, but you might not know its current value or purchase price - perhaps someone's been living there a while and haven't had a valuation recently. In that case, you could cut the constructor down to just three parameters, and allow the calling code to assign the others if they're known. Or better yet, overload the constructor with varying numbers of parameters. Just make sure you have some way of telling for sure whether a value has been assigned (for example, there may be some weird cases in which a sale price of zero is valid, but perhaps you know that -1 is never going to be valid). If you need to be really sure, use Nullable<T> and return null if it's not been assigned yet.

OTHER TIPS

In first place I'd recommend you not to use struct at all. Instead class should be used.

Value Type Usage Guidelines states that

It is recommended that you use a struct for types that meet any of the following criteria:

  1. Act like primitive types.
  2. Have an instance size under 16 bytes.
  3. Are immutable.
  4. Value semantics are desirable.

8 fields is way big for a struct for perfomance reasons. Also refer this for more info

You could use a parameterless (default) constructor, and rely on the type initializer synctax instead to initialze properties:

public class Apartment
{
    public Apartment()
    {
        // set default values
    }

    // define properties
    public int NumberOfBedRooms { get; set; }
    // ...
}

var apt = new Apartment {
  ApartmentSize = 100,
  NumberOfBedrooms = 3,
  NumberOfShowers = 2,
  CurrentMarketValue = 100000m,
  PurchasePrice = 100000m
}

This way you don't have to write constructor overloads, and users of your class can determine what to initialize.

A struct is, at its heart, a bunch of variables stuck together with duct tape. A struct with private fields may try to act like something else, but an struct with exposed public fields will act like a bunch of variable stuck together with duct tape. In cases where one wants to stick a bunch of variables together with duct tape, an exposed-field struct is often a perfect fit.

Note that Microsoft's guidelines assume that code will want everything to behave like an Object; they were also written before .NET supported generic types, when things generally couldn't be stored in collections without first casting them to Object. It is generally good to follow the guidelines in cases where one wants something whose semantics will be consistent with derivatives of Object(*). One should not follow them, however, if what one wants is simply to have a storage location (field, variable, etc.) hold a bunch of variables stuck together with duct tape. Many of the guidelines are in fact backward when applied to that particular scenario.

(*) A structure type storage location does not hold a derivative of Object, nor a reference to one; instead, it holds the concatenated contents of the structure's public and private fields. If a structure type is cast to a reference type, the system will create a new heap object with fields matching those of the structure, and copy the structure's fields to those of the new object; the resulting object will then behave largely as a class object with fields and methods matching those of the structure. If a structure does not follow the MS guidelines, the storage-location type and heap type will behave differently; MS assumes that's always a bad thing, but if one wants a storage location to hold a bunch of variables stuck together with duct tape, it's more useful to have a struct which cleanly behaves like that (something class can't do) than one which pretends to be a class object doing its best (rather clunky) emulation of such a thing.

Passing a structure as a value parameter will have about the same cost as passing all of the structure's public and private fields individually. Passing the struct as a reference parameter (either ref or out) has a fixed cost, regardless of the number of fields. Calling an instance method on a mutable storage location of structure type is equivalent to calling a method with an extra parameter ref StructType this at the start of its parameter list; if one attempts to call someStruct.Foo() on a temporary or immutable location, the compiler will silently substitute var temp = someStruct; temp.Foo();; because there is (still!) no way to tell the compiler that such substitution cannot safely be applied to a particular method, one should generally avoid writing methods where such substitution would not be safe.

With regard to your particular scenario, I think a simple exposed-field struct would likely be just about perfect. It allows parameter values to be set up in whatever sequence is convenient, makes it easy to construct multiple objects with similar but not identical parameters, etc. From a performance standpoint, taking the struct as a ref parameter might sometimes be a little faster than passing by value, but unless the same structure is passed multiple times I would expect passing by value should be just fine (if you use an exposed-field struct, I would expect that the JITter could probably produce code that was roughly equivalent to passing each struct field as a separate argument).

I would suggest you to do this:

You should create a class like this:

public class MyClass
{
    ...
    public int ApartmentSize{get;set;}
    ...
}

And in the Apartment class' constructor, do this:

Apartment(MyClass obj)
{
  // access the values like: obj.ApartmentSize  
}

Struct is overkill for this

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top