Lots of constructor parameters - Is there a better way? - c#

public class HourlyForecastData
{
public DateTime DateTime { get; private set; }
public decimal TemperatureCelcius { get; private set; }
public decimal DewPoint { get; private set; }
public string Condition { get; private set; }
public int ConditionCode { get; private set; }
public int WindSpeed { get; private set; }
public string WindDirection { get; private set; }
public decimal WindDegrees { get; private set; }
public int UltravioletIndex { get; private set; }
public decimal Humidity { get; private set; }
public decimal WindChill { get; private set; }
public int HeatIndex { get; private set; }
public decimal FeelsLike { get; private set; }
public decimal Snow { get; private set; }
public HourlyForecastData(DateTime dateTime, decimal temperatureCelcius, ...)
{
DateTime = dateTime;
TemperatureCelcius = temperatureCelcius;
//...set all the other properties via constructor
}
}
I am trying to learn better software design and OOP. I'm creating a library that can access a weather service that replies with XML. There are a lot of different fields provided by the service, so I've created properties for each of the XML fields. However, it feels a bit messy to have that number of properties set via the constructor. I could omit the constructor and have public setters but I'm trying to make an immutable class.
I've looked around at different design patterns for this and there seems to be some "Builder" and "Factory" patterns. However, I'm struggling to understand how I would apply that to my code. Or should I be using something completely different to fill the properties in these objects?

In this case composition might be a good fit. Especially since there are some parameters that belongs to specific categories.
For instance:
public int WindSpeed;
public string WindDirection;
public decimal WindDegrees;
Create a new object for them and then access the different values as:
weatherData.Wind.Speed;
and pass the new wind object to the constructor:
var wind = new Wind(xmlData.WindSpeed, xmlData.WindDirection, xmldata.WindDegrees);
var weatherReport = new WeatherReport(wind, /* .... */);
I would also introduce a few enums. Because as of now, the users of the weatherReport would for instance have to know which values the string WindDirection can have. If you convert the string to an enum instead it's a lot easier to use the different values.
A final note is that I typically only use constructors if the are some values that really have to be specified for the class to have a valid state. For instance, in your case the minimum valid state would be a date and the temperature? Then just put those in the constructor.

Re Is there a better OOP approach?
A large number of properties on a class can often indicate a need for splitting the class up (the Single Responsibility Principle of SOLID).
e.g. It would appear that HourlyForecastData models Wind (speed and direction), Precipitation (Snow, Dew and Rain), and Temperature (Min, Max ...) These concerns can be split into separate classes, and then the HourlyForecastData would be a composition of the three.
Re : Builder Pattern
The Builder Pattern can be useful to ease the burden during construction of large (often immutable) classes or graphs, but would obviously require additional (mutable) Builder class(es) to build up the target class representation (i.e. HourlyForecastData) and eventually create it (viz, by constructing it immutably by passing it all parameters to the constructor). So it isn't less effort, if that is what you required by 'better', but this can certainly can be easier to read e.g.:
HourlyForecastData todaysForecast = new HourlyForecastDataBuilder()
.WithBaseline(ObjectMother.WinterSnow) // Provide an archetype
.WithPrecipitation(snow: 5, rain:1) // Dew defaults to 0
.Build();
Baseline archetypes / object mothers would be useful if the weather patterns in an area were frequently stable and just required small adjustments. IMO builder pattern is most useful in Testing. I can't see an obvious fit in an Xml Serialization usage.
See also Named and Optional parameters
Re: Immutability
A private setter technically still allows mutability, although restricted within the class itself. C#6 and later supports getter-only auto properties which is the simplest form for implementing immutable properties
public class HourlyForecastData
{
public DateTime DateTime { get; }
...
public HourlyForecastData(DateTime dateTime, ...)
{
// Get only auto properties can only be set at construction time
DateTime = dateTime;
...
Unrelated, but Scala offers an even more concise syntax than C# for defining immutable public properties on a class, by declaring them once in the (primary) constructor:
class HourlyForecastData(val temperature: Int, val station: String, ...) {
}
Without the need for any further property or backing fields, whilst expressing and enforcing immutability. However, the burden still remains on the caller to provide all the parameters (whether directly, or via Builder, etc).
Re : Xml
If you are offering an API, I would suggest using WebAPI. Instead of building Xml serialization concerns into your DTO classes, I would suggest instead on relying on Content Negotiation. This will allow the caller to determine whether the data should be returned in Xml or JSON format.
* Note however that Xml Deserialization technologies often make use of reflection to populate DTO properties, which MAY require that the serializable properties have setters (even if private).

One way is to use a struct and pass it in instead. It also makes using the class easier as you only need to declare the struct state variable, change whatever differs from the "default" then pass it in.
public struct HourlyForecastDataState
{
public DateTime DateTime;
public decimal TemperatureCelcius;
public decimal DewPoint;
public string Condition;
public int ConditionCode;
public int WindSpeed;
public string WindDirection;
public decimal WindDegrees;
public int UltravioletIndex;
public decimal Humidity;
public decimal WindChill;
public int HeatIndex;
public decimal FeelsLike;
public decimal Snow;
}
public class HourlyForecastData
{
public DateTime DateTime { get; private set; }
public decimal TemperatureCelcius { get; private set; }
public decimal DewPoint { get; private set; }
public string Condition { get; private set; }
public int ConditionCode { get; private set; }
public int WindSpeed { get; private set; }
public string WindDirection { get; private set; }
public decimal WindDegrees { get; private set; }
public int UltravioletIndex { get; private set; }
public decimal Humidity { get; private set; }
public decimal WindChill { get; private set; }
public int HeatIndex { get; private set; }
public decimal FeelsLike { get; private set; }
public decimal Snow { get; private set; }
public HourlyForecastData(HourlyForecastDataState state)
{
DateTime = state.dateTime;
TemperatureCelcius = state.temperatureCelcius;
//...etc
}
}
//Usage:
HourlyForecastDataState HFDstate = new HourlyForecastDataState();
HFDstate.temperatureCelcius = 100 //omg, it's hot!
HourlyForecastData HFD = new HourlyForecastData(HFDstate);

Related

Creating class members during run time - C#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!
You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

Specifying a format inside of a class

I'm currently writing some software for a jumping-competition.
I've made a class to put my riders in and in this class theres also a variable to store the timing of the rider. I'm using a timespan for this as I also need to use milliseconds.
This is not a problem so far.
However, when I link my list with riders to a datagridview, the value of the time is being represented as 00:00:00 while I would need it to be 00:00.000
Is there a way that I can specify the outputstring either in my class or in my datagridview?
I know I could fill the datagridview manually and bypass the issue that way, but that doesn't really make sense.
So how can I tackle this problem?
Cheers,
Kenneth
public class RidersClass
{
public string firstnameRider { get; set; }
public string lastnameRider { get; set; }
public string nameHorse { get; set; }
public string Stable { get; set; }
public TimeSpan timeRound { get; set; }
public int penalty { get; set; }
}
Riders = new List<RidersClass>();
private void showList()
{
var source = new BindingSource();
source.DataSource = Riders;
grdRiders.DataSource = source;
}
One way to do it would be to create a wrapper class around TimeSpan like this
public class TimeSpanWrapper
{
public TimeSpan Time{get;set;}
public override string ToString()
{
return string.Format("{0}:{1}.{2}",Time.Hour,Time.Minute,Time.Second);
}
}
Then replace the TimeSpan object in your class with the TimeSpanWrapper, when the binding will occur for this class the ToString() method will be called and return the string in the format you like.

POCO's, ORM and immutability. How to make them work together?

Let's say I have the following C# class that I want to be immutable. You can only set it by using the parametrized constructor.
public class InsulineInjection
{
private InsulineInjection()
{
// We don't want to enable a default constructor.
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; private set; }
public DateTime DateTime { get; private set; }
public Millilitre Millilitre { get; private set; }
}
Now I would like to use an ORM to create this POCO. However, as far as I can see all .NET ORM's expects properties to be accessible and have a public constructor to be able to create this POCO. So I would have to change my POCO into this:
public class InsulineInjection
{
public InsulineInjection()
{
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get; set; }
}
This however makes my POCO mutable again. Someone using it could simply change any property afterwards which is not wat I want.
As far as I can see it, I could solve this in two different ways:
Write my own data access layer (or modify an orm) to be able to create correct POCO instances using the constructor I created.
Create some kind of mapper. Let the ORM create simple DTO objects and use the mapper to convert the DTO objects to my POCO at the appropriate time.
I'm leaning towards solution 2. Does someone have an example on how to do this? Or does someone have a better solution than the ones I describe above?
Many OR/Ms work as long as there is a default constructor and setters (no matter if they are public or not, they just have to exist)
So this wont work (no default constructor):
public class InsulineInjection
{
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
_millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get { return _millilitre; } }
}
or this (no setter for the last property)
public class InsulineInjection
{
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
_millilitre = millilitre;
}
public string Remark { get; set; }
public DateTime DateTime { get; set; }
public Millilitre Millilitre { get { return _millilitre; } }
}
While this will work:
public class InsulineInjection
{
protected InsulineInjection()
{
// works with many OR/Ms
}
public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
{
this.Remark = remark;
this.DateTime = dateTime;
this.Millilitre = millilitre;
}
public string Remark { get; private set; }
public DateTime DateTime { get; private set; }
public Millilitre Millilitre { get; private set; }
}
To avoid the constructor being used by your own code, you can use the Obsolete attribute
[Obsolete("Default constructor only here for the ORM", true)]
public InsulineInjection() {}
Passing true in the attribute will yield a compiler error if you actually call this constructor.
Not all .NET ORMs require public property access to write data.
NHibernate supports writing data to private fields or setters. However, you need to follow one of allowed naming conventions for fields so that it can deduce field name from the property name.
Check out NHibernate documentation about property mapping, particularly take a look at tables Table 5.1. Access Strategies and Table 5.2. Naming Strategies. Look at nosetter access strategy and pick naming strategy which fits your coding style.
This scenario is handled natively by dapper-dot-net.
You just need the order and type of the query fields to match the order and type of the constructor arguments. So for your class the query would be something like:
select millilitre,
,dateTime
,remark
from injections
Unfortunately dapper won't know how to convert something from decimal to millilitre.

Import a VB6 structure into C#

I've been tasked with converting some legacy code to a new system and we've got some VB6 structures that are here. Is there a way to convert them into a C# structure easily?
I could redefine the structure in C# but there's no fixed strings in C#. (Or maybe I misunderstand)
Any prods in the right direction?
Private Type MapRec
Name As String * NAME_LENGTH
Revision As Long
Moral As Byte
Up As Integer
Down As Integer
Left As Integer
Right As Integer
Music As String
BootMap As Integer
BootX As Byte
BootY As Byte
Tile() As TileRec
Npc(1 To MAX_MAP_NPCS) As Integer
NpcSpawn(1 To MAX_MAP_NPCS) As SpawnRec
TileSet As Integer
Region As Byte
End Type
With respect to fixed-length strings, yikes. It ain't gonna happen because there is no equivalent construct. Unless Jon Skeet or Anders Hejlsberg know differently and can be invoked to weigh in -- I don't think even they know a way, cuz there ain't one, I am pretty certain.
On the other hand, fixed-length strings are absolutely Satanic. Which is why they didn't include them in .NET. :-)
If you were to ask me how I would convert the above MapRec object to something usable in C#, well you kind of have your choice between a struct and a class. Personally, I dislike structs. If you used a class, then you could implement a kind of bastardized fixed-string by way of your setters and getters. As seen in this example, which is how I would implement your Type MapRec:
public class MapRec
{
private const int MAX_MAP_NPCS = 25;
private int fixedLength1 = 10;
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (value.Length != fixedLength1)
{
if (value.Length < fixedLength1)
{
_name = value.PadRight(fixedLength1);
}
else
{
_name = value.Substring(0,fixedLength1);
// or alternatively throw an exception if
// a 11+ length string comes in
}
}
else
{
_name = value;
}
}
}
// Constructor
public MapRec()
{
Npc = new int[MAX_MAP_NPCS];
NpcSpawn = new SpawnRec[MAX_MAP_NPCS];
}
public long Revision { get; set; }
public byte Moral { get; set; }
public int Up { get; set; }
public int Down { get; set; }
public int Left { get; set; }
public int Right { get; set; }
public string Music { get; set; }
public int BootMap { get; set; }
public byte BootX { get; set; }
public byte BootY { get; set; }
public TileRec[] Tile { get; set; }
public int[] Npc { get; set; }
public SpawnRec[] NpcSpawn { get; set; }
public int TileSet { get; set; }
public byte Region { get; set; }
}
In the end, unless one actually needs a fixed-length string (and perhaps Microsoft.VisualBasic.VBFixedStringAttribute could do the job), I would suggest staying the heck away from them.
You may be interested in the VBFixedStringAttribute, and the VBFixedArrayAttribute although they are only utilized in a few places.
See also this question and this question.

Why Does Lack of Cohesion Of Methods (LCOM) Include Getters and Setters

I am looking at the LCOM metric as shown here,
http://www.ndepend.com/Metrics.aspx
So we are saying a few things,
1) A class is utterly cohesive if all its methods use all its instance fields
2) Both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods
If I look at a class such as this,
public class Assessment
{
public int StartMetres { get; set; }
public int EndMetres { get; set; }
public decimal? NumericResponse { get; set; }
public string FreeResponse { get; set; }
public string Responsetype { get; set; }
public string ItemResponseDescription { get; set; }
public string StartText { get; set; }
public decimal? SummaryWeight { get; set; }
}
It gets a bad score of 0.94 because each getter and setter doesn't access 'all of the other instance fields'.
It is calculated like this,
accessAverage - methodCount / 1 - methodCount
(2 - 17) / (1 - 17) = 0.94 (rounded)
I am not understanding this metric, why should it include getters and setters? A getter and setter will always only access one single instance field.
This demonstrates that every software metric is flawed if you blindly take it to its extreme.
You know an "incohesive" class when you see one. For example:
class HedgeHog_And_AfricanCountry
{
private HedgeHog _hedgeHog;
private Nation _africanNation;
public ulong NumberOfQuills { get { return _hedgeHog.NumberOfQuills; } }
public int CountOfAntsEatenToday { get { return _hedgeHog.AntsEatenToday.Count(); } }
public decimal GrossDomesticProduct { get { return _africanNation.GDP; } }
public ulong Population { get { return _africanNation.Population; } }
}
This is obviously an incohesive class, because it contains two pieces of data that don't need to be with one another.
But while it's obvious to us that this class is incohesive, how can you get a software program to determine incohesion? How would it tell that the above class is incohesive, but this isn't?
class Customer
{
public string FullName { get; set; }
public Address PostalAddress { get; set; }
}
The metric they came up with certainly detects incohesion, but also comes up with false positives.
What if you decided this metric was important? You could create a "CustomerData" class containing just fields, and a "Customer" class that exposes the data fields as properties.
// This has no methods or getters, so gets a good cohesion value.
class CustomerData
{
public string FullName;
public Address PostalAddress;
}
// All of the getters and methods are on the same object
class Customer
{
private CustomerData _customerData;
public string FullName { get { return _customerData.FullName; } }
// etc
}
But if I'm playing this game, I can apply it to the incohesive example as well:
class Hedgehog_And_AfricanCountry_Data
{
public Hedgehog _hedgehog;
public AfricanNation _africanNation;
}
class Hedgehog_And_AfricanCountry
{
private Hedgehog_And_AfricanCountry_Data _hedgehogAndAfricanCountryData;
// etc;
}
Really, I think it's best to understand what cohesion is, and why it's a worthwhile goal, but also understand that a software tool can not properly measure it.

Categories