What do you think of using properties as object initializers in C#; - c#

I was wondering what people thought of using properties as object initializers in C#. For some reason it seems to break the fundamentals of what constructors are used for.
An example...
public class Person
{
string firstName;
string lastName;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName= value; }
}
}
Then doing object intialization with.....
Person p = new Person{ FirstName = "Joe", LastName = "Smith" };
Person p = new Person{ FirstName = "Joe" };

What you see here is some syntatic sugar provided by the compiler. Under the hood what it really does is something like:
Person p = new Person( FirstName = "Joe", LastName = "Smith" );
Person _p$1 = new Person();
_p$1.FirstName = "Joe";
_p$1.LastName = "Smith";
Person p = _p$1;
So IMHO you are not really breaking any constructor fundamentals but using a nice language artifact in order to ease readability and maintainability.

Object initializers does in no way replace constructors. The constructor defines the contract that you have to adhere to in order to create a instance of a class.
The main motivation for object initializers in the C# language is to support Anonymous Types.
var v = new { Foo = 1, Bar = "Hi" };
Console.WriteLine(v.Bar);

IMHO its sweet. Most objects are newed up with the default constructor, and must have some properties set before they are ready to run; so the object initializers make it easier to code against most objects out there.

Constructors should only really have arguments that are required to construct the object. Object initialisers are just a convenient way to assign values to properties. I use object initialisers whenever I can as I think it's a tidier syntax.

Since you're already using the new C# syntax, might as well use automatic properties as well, just to sweeten up your code a drop more:
instead of this:
string firstName;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
use this:
public string FirstName { get; set; }

I think overall it is useful, especially when used with automatic properties.
It can be confusing when properties are doing more than get/set.
Hopefully this will lead to more methods, and reduce the abuse of properties.

Not your original question, but still...
Your class declaration can be written as:
public class Person
{
public string FirstName { get; set; }
public string LastName {get; set; }
}
and if it were my code, I'd probably have an object for Name with fields First and Last.

It's also quite necessary for projected classes returned from a language integrated query (linq)
var qry = from something in listofsomething
select new {
Firstname = something.FirstName,
Lastname = something.Surname
}

Adding to Nescio's thoughts - I'd suggest in code reviews actively hunting down expensive transparent operations in property accessors e.g. DB round tripping.

Object Initializers help to reduce coding complexity in that you don't need to create a half dozen different constructors in order to provide initial values for properties. Anything that reduces redundant code is a positive, in my book.
I believe the primary reason the feature was added to the language is to support anonymous types for LINQ.

If you want to enforce the use of a constructor, you could set your object's default parameterless constructor to private, and leave public only some enforced constructors:
public class SomeObject
{
private SomeObject()
{}
public SomeObject(string someString) //enforced constructor
{}
public string MyProperty { get; set; }
}
Using the above definition, this throws an error:
var myObject = new SomeObject { MyProperty = "foo" } //no method accepts zero arguments for constructor
Of course this can't be done for all cases. Serialization, for example, requires that you have a non-private default constructor.

I for one am not happy with them. I don't think they have a place in the constructor, or MS should got back and refactor them to allow you to use them in a private fasion. If I construct an object I want to pass in some PRIVATE data. I want it set from the outside world once and that's it. With Object Initializers you allow the values passed into the constructor to be modifiable.
Maybe in the future they will change this.

Related

Modify a C# Class to be a Collection

Below is a Person class. Currently, it can only be used to instantiate a single Person object. I would like to change it so it can accept a list of full names and result in a collection of Person objects.
using System;
namespace Test
{
public class Person
{
public string FullName;
public string Organization;
public Person(string Organization, string FullName)
{
this.FullName = FullName;
this.Organization = Organization;
}
}
}
This would ideally be similar to the Fileinfo class. This class can be initialized by either providing a single file name or a list of file names. I would also like to be able to initialize this Person class to be constructed using either a list of full names or a single name.
I don't think the FileInfo class works the way you're expecting—but I now understand what you're asking. As mentioned in the comments, you're going to need two classes. The first one is for your business object—in this case Person. The second one will be a collection-based class, such as PersonCollection.
As an alternative, you can alter your data model so that you have a separate Organization and Person class. In that model, your Person class would have a FullName property, but not an Organization property. I'll address that option at the end.
Instead of just offering code, I'll attempted to explain the concepts as I go, while also flagging issues you're likely going to run into along the way. That makes for a longer post. But given the nature of the question, I hope this additional detail will prove valuable.
Business Object
Your Person class can continue to operate exactly the way you've proposed. That said, there are a couple of improvements you might consider.
First, if your business object is never going to be modified after you've instantiated it—i.e., it's immutable—then you can use the C# 9.0 record syntax, which allows your constructor to define properties directly:
public record Person(string Organization, string FullName);
Alternatively, if you prefer to keep this as a class, then I'd recommend implementing it as follows:
public class Person
{
public string Organization { get; set; }
public string FullName { get; set; }
public Person(string organization, string fullName)
{
Organization = organization;
FullName = fullName;
}
}
Notes
I've used the auto-implemented property syntax for Organization and FullName; otherwise, they will be treated as public fields, which have slightly different semantics (source).
I've updated your parameter names to be camelCase, so you don't need to assign property values with the this prefix. This is standard in C#.
I think it's more intuitive for the fullName to be your first parameter, but that's a stylistic preference, so I've kept this consistent with your original code.
Collection-Based Class
There are a number of ways to create a strongly typed collection-based class. The easiest is to simply inherit from Collection<Person>:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people)
{
Add(person);
}
}
}
Notes
You could also call this People, as I did in the comments, but Microsoft recommends that strongly typed collection classes start with the item type (i.e., Person) and end with Collection (source).
You could also derive from e.g., List<Person>, but Microsoft recommends using the more familiar Collection<> class (source).
The params keyword allows you to accept an array—in this case of Person objects—but pass them as a list of parameters, instead of an array (details). This makes for a friendlier and more intuitive interface in this case.
You could instead accept an array of strings—e.g., fullNames—in order to construct a new Person object for each one, as you requested. But as your current Person object also needs an Organization parameter, it's easier to first construct the Person object, and then pass it to the collection.
Usage
You can now construct the class by creating some Person instances and passing them to the PersonCollection constructor as follows:
//Construct some Person objects
var robert = new Person("Robert, Inc.", "Robert");
var jeremy = new Person("Ignia, LLC", "Jeremy")
//Construct a new PersonCollection
var people = new PersonCollection(robert, jeremy);
Alternatively, if you're using C# 9.0 (e.g., with .NET 5+), and are hard-coding your Person initializers, you can also use the following syntactical shorthand:
var people = new PersonCollection(
new ("Robert, Inc.", "Robert"),
new ("Ignia, LLC", "Jeremy")
);
This looks similar to your request to pass in a list of full names—except that it accounts for your Organization property, and results in a full Person object for each. If you'd truly prefer to just pass in an array of names, see Organization-Based Model at the end of this answer.
Validation
In practice, you probably want to add in some validation to ensure that each Person reference is not null, and that at least one Person instance is passed to your constructor. If so, you can extend this to include some validation. Here's one possible approach to that:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people?? Array.Empty<Person>())
{
if (person is null)
{
continue;
}
Add(person);
}
if (Count == 0)
{
throw new ArgumentNullException(nameof(people));
}
}
}
I default to the Array.Empty<Person> on the loop so that we don't need to do two checks—first for the people length, and then for the PersonCollection length. But you can adjust to your preferences.
Organization-Based Model
In the comments, you proposed an alternate constructor:
public People(string Organization, string[] FullName) { … }
This implies a different data model. If you're going to have one organization that can have multiple Persons associated with it, I'd instead create an Organization business object:
public record Person(FullName);
public class Organization
{
public readonly string Name { get; }
public readonly Collection<Person> Members { get; }
public Organization(string name; params string[] members)
{
Name = name?? throw new ArgumentNullException(nameof(name));
foreach (var memberName in members)
{
Members.Add(new Person(memberName));
}
}
}
Notes
In this model, each Organization has a Name and then multiple Members—each represented by a Person object.
Because the organization name is handled at the Organization level, it is presumably not needed on each Person object.
The Members collection could be replaced with a Collection<string> if you just need a list of names. But maintaining a Person object offers more flexibility.
You can obviously incorporate the previously proposed validation logic into this constructor as well.
You could also add an overload of the constructor that accepts a Person[] array to offer more flexibility.

C# How to change the type of value field in set accessor?

I'm new to C# and I was trying to use set accessor to add a new Person object to a Person List called children in my class Person with the following approach, but also I want to use the get accessor to return an array of Persons.
the problem is that the value field in set accessor is an array of Person and I don't want it to be like that, I want it to be an Instance of Person NOT an array of persons, so I can add it to the List
class Person
{
private string firstName;
private string lastName;
public string FullName
{
get
{
return firstName + lastName;
}
}
public readonly DateTime dateOfBirth;
public readonly FavoriteColor favoriteColor;
private List<Person> children;
public Person[] Children
{
get
{
return children.ToArray();
}
set
{
children.Add(value);
}
}
}
So is there any thing that I can do to achieve that in C# using properties?
It's not possible to have different type for the getter and setter on the same property. Neither would it make much sense, in most cases. You could use a different property for getting and setting:
public Person[] Children => children.ToArray();
public Person LatestChild
{
set { this.children.Add(value); }
}
But honestly just adding an AddChild method would probably be a better idea.
public Person[] Children => children.ToArray();
public void AddChild(Person child)
{
children.Add(value);
}
If overloading an assignment (single =) was supported, you could perhaps do this.
That said, overloading assignment operators is not supported in the language (here's a few informal references: 1, 2).
What you're doing is not idiomatic of the language, and thus I discourage you from even trying to do this. You're attempting to redefine an operation in a way that won't be intuitive or obvious to other readers of your code.
Instead, provide an explicit method that adds the value to the array (by the way, that means allocating a new array, as arrays have fixed bounds); this makes your intent clear. You could go the route of overloading +, which overloads +=, but this is still getting out of the realm of the language's idioms, and so should probably be discouraged).
The setter expects an object of type Person[], because that's how you defined the property.
Make the array property read-only by removing the setter and add an Add(Person person) method to your class instead.

C# : assign data to properties via constructor vs. instantiating

Supposing I have an Album class :
public class Album
{
public string Name {get; set;}
public string Artist {get; set;}
public int Year {get; set;}
public Album()
{ }
public Album(string name, string artist, int year)
{
this.Name = name;
this.Artist = artist;
this.Year = year;
}
}
When I want to assign data to an object of type Album, what is the difference between the next 2 approaches :
Via Constructor
var albumData = new Album("Albumius", "Artistus", 2013);
or when instantiating
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
Both approaches call a constructor, they just call different ones. This code:
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
is syntactic shorthand for this equivalent code:
var albumData = new Album();
albumData.Name = "Albumius";
albumData.Artist = "Artistus";
albumData.Year = 2013;
The two are almost identical after compilation (close enough for nearly all intents and purposes). So if the parameterless constructor wasn't public:
public Album() { }
then you wouldn't be able to use the object initializer at all anyway. So the main question isn't which to use when initializing the object, but which constructor(s) the object exposes in the first place. If the object exposes two constructors (like the one in your example), then one can assume that both ways are equally valid for constructing an object.
Sometimes objects don't expose parameterless constructors because they require certain values for construction. Though in cases like that you can still use the initializer syntax for other values. For example, suppose you have these constructors on your object:
private Album() { }
public Album(string name)
{
this.Name = name;
}
Since the parameterless constructor is private, you can't use that. But you can use the other one and still make use of the initializer syntax:
var albumData = new Album("Albumius")
{
Artist = "Artistus",
Year = 2013
};
The post-compilation result would then be identical to:
var albumData = new Album("Albumius");
albumData.Artist = "Artistus";
albumData.Year = 2013;
Object initializers are cool because they allow you to set up a class inline. The tradeoff is that your class cannot be immutable. Consider:
public class Album
{
// Note that we make the setter 'private'
public string Name { get; private set; }
public string Artist { get; private set; }
public int Year { get; private set; }
public Album(string name, string artist, int year)
{
this.Name = name;
this.Artist = artist;
this.Year = year;
}
}
If the class is defined this way, it means that there isn't really an easy way to modify the contents of the class after it has been constructed. Immutability has benefits. When something is immutable, it is MUCH easier to determine that it's correct. After all, if it can't be modified after construction, then there is no way for it to ever be 'wrong' (once you've determined that it's structure is correct). When you create anonymous classes, such as:
new {
Name = "Some Name",
Artist = "Some Artist",
Year = 1994
};
the compiler will automatically create an immutable class (that is, anonymous classes cannot be modified after construction), because immutability is just that useful. Most C++/Java style guides often encourage making members const(C++) or final (Java) for just this reason. Bigger applications are just much easier to verify when there are fewer moving parts.
That all being said, there are situations when you want to be able quickly modify the structure of your class. Let's say I have a tool that I want to set up:
public void Configure(ConfigurationSetup setup);
and I have a class that has a number of members such as:
class ConfigurationSetup {
public String Name { get; set; }
public String Location { get; set; }
public Int32 Size { get; set; }
public DateTime Time { get; set; }
// ... and some other configuration stuff...
}
Using object initializer syntax is useful when I want to configure some combination of properties, but not neccesarily all of them at once. For example if I just want to configure the Name and Location, I can just do:
ConfigurationSetup setup = new ConfigurationSetup {
Name = "Some Name",
Location = "San Jose"
};
and this allows me to set up some combination without having to define a new constructor for every possibly permutation.
On the whole, I would argue that making your classes immutable will save you a great deal of development time in the long run, but having object initializer syntax makes setting up certain configuration permutations much easier.
Second approach is object initializer in C#
Object initializers let you assign values to any accessible fields or
properties of an object at creation time without having to
explicitly invoke a constructor.
The first approach
var albumData = new Album("Albumius", "Artistus", 2013);
explicitly calls the constructor, whereas in second approach constructor call is implicit. With object initializer you can leave out some properties as well. Like:
var albumData = new Album
{
Name = "Albumius",
};
Object initializer would translate into something like:
var albumData;
var temp = new Album();
temp.Name = "Albumius";
temp.Artist = "Artistus";
temp.Year = 2013;
albumData = temp;
Why it uses a temporary object (in debug mode) is answered here by Jon Skeet.
As far as advantages for both approaches are concerned, IMO, object initializer would be easier to use specially if you don't want to initialize all the fields. As far as performance difference is concerned, I don't think there would any since object initializer calls the parameter less constructor and then assign the properties. Even if there is going to be performance difference it should be negligible.

A good design to pack parameters?

I have an object that takes plenty of parameters to its constructor (from 9 to 13 depending on use).
I want to avoid the ugliness of new MyObject(param1, param2, param3 ... param13).
My first attempt was to create a class MyObjectParams with properties with public getters and setters, it gives something like that :
var objectParams = new MyObjectParams
{
Param1 = ...,
Param2 = ...,
...
};
I see some big projects like SlimDX for their PresentParameters use this design. It looks better. But the class is not immutable.
I'd like my MyObjectParams to be immutable while still using a clean construction style. This is how it would look like with an immutable class :
var objectParams = new MyObjectParams
(
param1,
param2,
...
);
Note: it's just the long constructor line broken into several, so it's cleaner but still not as readable as initializers.
I was thinking of using named parameters to get both an immutable class and a more or less clean code, but I'm not sure whether this actually is a good idea:
var objectParams = new MyObjectParams
(
param1: ...,
param2: ...,
...
);
Should I use named parameters? Can you think of a better approach to solve this problem?
Edited regarding an answer below: unfortunately, I don't really think the design is bad. The 9 parameters really are required and remain constant throughout the entire life of the object. I cannot provide a default value for them as it is completely usage-dependant.
Have you looked into designing a solution in which you wouldn't need this amount of parameters? Having a lot of parameters makes the code very tightly coupled which reduces maintainability. Maybe you can redesign a small amount of code to a design which better separates the responsibilities of the class?
I really like the way The Zen of Python says a few things:
Simple is better than complex.
Complex is better than complicated.
[...]
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
I believe that having a dedicated Options class of some kind with the exhaustive list of all possible parameters is a good idea. Allow your MyObject constructor to require an Options instance, and then store a reference to the instance as a field on MyObject and refer to its getters/setters. (Storing the reference will be much superior to trying to parse the options and transfer their values to the MyObject instance. Now that would be messy.) With all data access delegated to the Options class, you will have successfully encapsulated the object's configuration, and you've designed a simple API for option access as the same time.
If Options has no reason to be publicly accessible, make it a private class definition and then you're free to maintain changes to Options logic without modifying MyObject. I believe that is a fair solution to you as the developer, and doesn't commit atrocities.
The constructor could have only a small number of parameters, the ones required for proper object initialization. You could then have a number of properties that can be set after the object has been constructed. You can set default values for those properties in the constructor and the client can set the ones he/she requires.
class Person
{
public Person(string name, int age)
{
Name = name;
Age = age;
Address = "Unknown";
Email = "Unknown";
}
public string Name {get; private set;}
public int Age {get; private set;}
public string Email {get; set;}
public string Address {get; set;}
}
Person p = new Person("John Doe", 30);
p.Email = "john.doe#example.org";
You could use the builder pattern to construct an immutable object.
public sealed class ComplexObject
{
public int PropA { get; private set; }
public string PropB { get; private set; }
public sealed class Builder
{
int _propA;
string _propB;
public Builder SetPropA(int propA)
{
// validate
_propA = propA;
return this;
}
public Builder SetPropB(string propB)
{
// validate
_propB = propB;
return this;
}
public CustomObject ToCustomObject()
{
return new CustomObject
{
PropA = _propA,
PropB = _propB
};
}
}
}
Usage
var custom =
new CustomObject.Builder()
.SetPropA(1)
.SetPropB("Test")
.ToCustomObject();
Final Thoughts
Despite my previous suggestion I am in no way against using named parameters if they are available.

Constructors with the same argument type

I have a Person object with two constructors - one takes an int (personId), the other a string (logonName). I would like another constructor that takes a string (badgeNumber). I know this can't be done, but seems it might be a common situation. Is there a graceful way of handling this? I suppose this would apply to any overloaded method. Code:
public class Person
{
public Person() {}
public Person(int personId)
{
this.Load(personId);
}
public Person(string logonName)
{
this.Load(logonName);
}
public Person(string badgeNumber)
{
//load logic here...
}
...etc.
You could perhaps use factory methods instead?
public static Person fromId(int id) {
Person p = new Person();
p.Load(id);
return p;
}
public static Person fromLogonName(string logonName) {
Person p = new Person();
p.Load(logonName);
return p;
}
public static Person fromBadgeNumber(string badgeNumber) {
Person p = new Person();
// load logic
return p;
}
private Person() {}
You might consider using custom types.
For example, create LogonName and BadgeNumber classes.
Then your function declarations look like...
public Person(LogonName ln)
{
this.Load(ln.ToString());
}
public Person(BadgeNumber bn)
{
//load logic here...
}
Such a solution might give you a good place to keep the business logic that governs the format and usage of these strings.
You have four options that I can think of, three of which have already been named by others:
Go the factory route, as suggested by several others here. One disadvantage to this is that you can't have consistent naming via overloading (or else you'd have the same problem), so it's superficially less clean. Another, larger, disadvantage is that it precludes the possibility of allocating directly on the stack. Everything will be allocated on the heap if you take this approach.
Custom object wrappers. This is a good approach, and the one I would recommend if you are starting from scratch. If you have a lot of code using, e.g., badges as strings, then rewriting code may make this a non-viable option.
Add an enumeration to the method, specifying how to treat the string. This works, but requires that you rewrite all the existing calls to include the new enumeration (though you can provide a default if desired to avoid some of this).
Add a dummy parameter that is unused to distinguish between the two overloads. e.g. Tack a bool onto the method. This approach is taken by the standard library in a few places, e.g. std::nothrow is a dummy parameter for operator new. The disadvantages of this approach are that it's ugly and that it doesn't scale.
If you already have a large base of existing code, I'd recommend either adding the enumeration (possibly with a default value) or adding the dummy parameter. Neither is beautiful, but both are fairly simple to retrofit.
If you are starting from scratch, or only have a small amount of code, I'd recommend the custom object wrappers.
The factory methods would be an option if you have code which heavily uses the raw badge/logonName strings, but doesn't heavily use the Person class.
No.
You might consider a flag field (enum for readability) and then have the constructor use htat to determine what you meant.
That won't work. You might consider making a class called BadgeNumber that wraps a string in order to avoid this ambiguity.
You cannot have two different constructors/methods with the same signature, otherwise, how can the compiler determine which method to run.
As Zack said, I would consider creating an "options" class where you could actually pass the parameters contained in a custom type. This means you can pretty much pass as many parameters as you like, and do what you like with the options, just be careful you dont create a monolithic method that tries to do everything..
Either that, or vote for the factory pattern..
You could use a static factory method:
public static Person fromLogon(String logon) { return new Person(logon, null); }
public static Person fromBadge(String badge) { return new Person(null, badge); }
As has been suggested, custom types is the way to go in this case.
If you are using C# 3.0, you can use Object Initializers:
public Person()
{
}
public string Logon { get; set; }
public string Badge { get; set; }
You would call the constructor like this:
var p1 = new Person { Logon = "Steve" };
var p2 = new Person { Badge = "123" };
Only thing I can think of to handle what you're wanting to do is to have to params, one that describes the param type (an enum with LogonName, BadgeNumer, etc) and the second is the param value.
You could switch to a factory style pattern.
public class Person {
private Person() {}
public static PersonFromID(int personId)
{
Person p = new Person().
person.Load(personID);
return p;
this.Load(personId);
}
public static PersonFromID(string name)
{
Person p = new Person().
person.LoadFromName(name);
return p;
}
...
}
Or, as suggested, use custom types. You can also hack something using generics, but I wouldn't recommend it for readability.
Depending on your business constraints:
public class Person
{
public string Logon { get; set; } = "";
public string Badge { get; set; } = "";
public Person(string logon="", string badge="") {}
}
// Use as follow
Person p1 = new Person(logon:"MylogonName");
Person p2 = new Person(badge:"MyBadge");
How about ...
public Person(int personId)
{
this.Load(personId);
}
public Person(string logonName)
{
this.Load(logonName);
}
public Person(Object badgeNumber)
{
//load logic here...
}

Categories

Resources