Imagine a class which can, in principle, be created by specifying the value of one of two properties, both of which happen to have the same type. The following code accomplishes this by using a combination of named and optional parameters to discriminate between the two constructors:
class Program
{
static void Main()
{
//Note: these 2 ctors are distinguished only by the argument naming convention:
thing thingWithMass = new thing(mass: 10);
thing thingWithVolume = new thing(vol: 25);
}
class thing
{
int Density = 3;
int Mass;
int Vol;
public thing(int mass)
{
Mass = mass;
Vol = Mass/Density;
}
// Note the use of the optional variable to distinguish this ctor:
public thing(int vol, bool isVol=true)
{
Vol = vol;
Mass = Vol * Density;
}
}
}
So (somewhat surprisingly) this code compiles and works perfectly, but is it bad form? It seems a bit like trickery, and I'm wondering if there is a lurking danger that isn't readily apparent to me? Does it smell?
NOTE: In this particular case, I realize that I could accomplish essentially the same thing with a single constructor that looks like this:
public thing(int mass=0, int vol=0) //plus a couple of if() statements in the body
but in my real situation there are quite a few other parameters involved, and combining them all into one constructor gets a bit unwieldy and hard to read.
If your class has many constructors with very different logic and conflicting types of arguments, consider using static factory methods:
public static Thing CreateFromMass(int mass)
{
return new Thing(mass, 0);
}
public static Thing CreateFromVol(int vol)
{
return new Thing(0, vol);
}
You can make your constructor non-public if you use factory methods like this.
Distinguishing constructors based on parameter names, while possible, is not recommended, because it is very uncommon in C#. Note that you are also forced to use tricks with optional parameters to achive this — a clear indicator that you are doing something wrong.
IMO it's a bit of a smell. What if a consumer calls thing(10, false). That has the unintended consequence of creating thing with the wrong value.
I can think of two possible solutions
1) Use a factory as described by Athari.
2) Create types for Mass and Volume. For example,
class Mass
{
private readonly int _mass;
public Mass(int mass) { _mass = mass; }
public int Value { get { return _mass; } }
}
class Volume
{
private readonly int _volume;
public Mass(int volume) { _volume = volume; }
public int Value { get { return _volume; } }
}
You can then change your signatures to
thing(Volume volume)
thing(Mass mass)
In response to your comment about simple arithmetic operations not working with the second approach, you can define implicit conversions to and from int for Mass and Volume.
abstract class Number
{
public static implicit operator int(Number number)
{
return number.Value;
}
public abstract int Value { get; set; }
}
internal class Mass : Number
{
public override int Value { get; set; }
public static implicit operator Mass(int val) { return new Mass(){ Value = val }; }
}
internal class Volume : Number
{
public static implicit operator Volume(int val) { return new Volume(){ Value = val }; }
public override int Value { get; set; }
}
var mass = new Mass { Value = 10 };
var volume = new Volume { Value = 20 };
int product = mass * volume; // should work
mass = 10 * 20; // should also work
Related
this is a problem I'm not sure how to call it or how name the things I want to do but hopefully the code examples can speak for themselves. I come from a PHP background and am learning .NET Core 2.2/3.0. Something I'm running into right now though is how I can avoid some code duplication when creating similar classes. For example I want to create multiple value objects that basically just contain strings, but each value object has different constraints. In most cases however the only constraint differences are in the length.
So in PHP I would do something like this:
abstract class Text
{
abstract public static function maxCharacters(): int;
protected $value;
public function __construct(string $text)
{
if (mb_strlen($text) > static::maxCharacters()) {
throw new LengthException(sprintf('Too many characters, the max is %d.', static::maxCharacters()));
}
$this->value = $text;
}
public function value(): string
{
return $this->value;
}
}
class Name extends Text
{
public static function maxCharacters(): int
{
return 50;
}
}
class Description extends Text
{
public static function maxCharacters(): int
{
return 1000;
}
}
It's not the best example of inheritance, but the goal is to illustrate the point in that I would like to have 1 place where I can put my validation logic, and then in the subclass only have to define the parameters of the validation and not the actual logic to perform the validation.
Since we're dealing with value objects here I assume that in C# it would be best to use a (readonly) struct. So, without any inheritance, what I ended up with as the C# equivalent is:
public readonly struct Name
{
private const int MAX_CHARACTERS = 50;
public string Value
{
get { return this.Value; }
set
{
if (value.Length > Name.MAX_CHARACTERS)
{
throw new ArgumentOutOfRangeException(String.Format("Too many characters, the max is {0}.", Name.MAX_CHARACTERS));
}
this.Value = value;
}
}
public Name(string name) => this.Value = name;
}
public readonly struct Description
{
private const int MAX_CHARACTERS = 1000;
public string Value
{
get { return this.Value; }
set
{
if (value.Length > Description.MAX_CHARACTERS)
{
throw new ArgumentOutOfRangeException(String.Format("Too many characters, the max is {0}.", Description.MAX_CHARACTERS));
}
this.Value = value;
}
}
public Description(string description) => this.Value = description;
}
But as you can see without inheritance that's a lot of copy/paste, and copy/paste is something I prefer to avoid. The only alternative I could think of is to create a separate TextValidator class or something that I can call from the set to which I would only have to pass the max number of characters, but that would still leave me with more copy/paste than I'd prefer.
How would you write something like this in C# with as little copy/paste as possible?
It seems like you've got the basics of inheritance understood in your PHP example; I'd just suggest doing a bit of reading on the syntax in C#.
For what it's worth, the following would do the trick:
public abstract class Text{
public string Value { get; }
public Text(string val) {
if (val.Length > MAX) throw new Exception();
Value = val;
}
protected abstract int MAX{get;}
}
public class Name : Text{
public Name(string val): base(val) { }
protected override int MAX => 50;
}
public class Description : Text
{
public Description(string val) : base(val) { }
protected override int MAX => 1000;
}
I'll also add a footnote to say be careful calling abstract methods/properties from a class constructor (which is what I'm doing here). If, for example, the value of MAX is a computed value which depends on the object already having been initialized, you could run into some issues. In this case though, it won't be a problem.
This question already has answers here:
When do you use the "this" keyword? [closed]
(31 answers)
Closed 5 years ago.
The older apprentices in my company use "this." a lot.
Two weeks ago I started coding object-oriented and still don't get for what it is being used.
You need to understand what instance is first. Let's say you have an object:
public class House
{
public decimal Height { get; set; }
}
You can have multiple instances of it:
var smallHouse = new House { Height = 100M };
var bigHouse = new House { Height = 300M };
Each instance has its own value of Height. When you want to work with Height in a method of House, you need to refer to the current instance method is operating at (the one consumer called).
This can be done explicitly by using this as a special kind of variable that refers to this current instance:
public class House
{
public decimal Height { get; set; }
public bool IsItTooBig()
{
return this.Height > 200;
}
}
Or you can omit this and let C# guess that what you mean is the instance value:
public class House
{
public decimal Height { get; set; }
public bool IsItTooBig()
{
return Height > 200;
}
}
Programmers differ in opinion whether it's good or bad to be explicit there. If you follow capitalization conventions, you can distinguish instance state and method scope state (normal variables) by it.
There are cases where you absolutely need it, for example when you have naming conflict, or when you want to return current instance from a method:
public class House
{
public decimal Height { get; set; }
public House AddFloor()
{
Height += 100;
return this;
}
}
You should consider applying immutability in many of these cases though.
The keyword 'this' represents the instance of an object used to explicitly call a method, field or property of that instance.
Commonly used when your private fields have the same name as the parameters in a given method:
private string name;
public void SetName(string name) {
this.name = name;
}
When you want to refer to instance field within that class you use this, it can be omitted but there are cases it can not be omitted.
public class InstanceClass
{
int field = 10;
public void Method()
{
int field = 0;
Console.WriteLine(field); // outputs 0
Console.WriteLine(this.field); // outputs 10 because "this" refers to field.
}
}
if there is no declared local variable that conflicts with field name, "this" can be omitted.
public class InstanceClass
{
int _field = 10;
public void Method()
{
int field = 0;
Console.WriteLine(field);
Console.WriteLine(_field); // prefixed with _.
// no conflicts
// so "this" can be omitted.
}
}
another case where you can not omit this, is when you use indexer.
public class InstanceClass
{
private List<int> _source;
private int offset;
public int this[int index] // you use "this"
{
get => _source[index + offset]
set => _source[index + offset] = value;
}
public void Method()
{
var first = this[0]; // must use "this" to refer to indexer for this class.
}
}
"this" is used for calling constructor overloads too.
public class Foo
{
public Foo() : this(0)
{
Console.WriteLine("world");
}
public Foo(int param1)
{
Console.WriteLine("Hello");
}
}
//...
var foo = new Foo(); // outputs "Hello world"
"this" also refers to instance of class itself. so if you want to return instance of self you use this.
public class Foo
{
public Foo ReturnMe() // weird example.
{
return this;
}
}
I would like to design something that gets the distance between two things. However, these things can be manifest in many obnoxious forms.
Let's say we have a set of classes. (Not necessarily base and derived)
Cat, CoolCat, ReallyCoolCat
All of them have a way to access a position. I would like to write a function call 'DistanceBetween' that gets the distances between the cats.
I can make overloads:
public static float DistanceBetween(Cat cat1, Cat cat2)
{
return Mathf.Abs(cat1.position - cat2.position);
}
public static float DistanceBetween(CoolCat cat1, CoolCat cat2)
{
return Mathf.Abs(cat1.transform.position, cat2.transform.position);
}
// ... etc...
However, then I would have cases where I need to know the distance between a Cat and a CoolCat or the distance between a CoolCat and a ReallyCoolCat. That means...
public static float DistanceBetween(Cat cat1, CoolCat cat2)
{
return Mathf.Abs(cat1.position, cat2.transform.position);
}
public static float DistanceBetween(CoolCat cat1, ReallyCoolCat cat2)
{
return Math.Abs(cat1.tranform.position, cat2.kittyVariables.position);
}
// ... etc ...
But then it just seems arbitrary cause I can rearrange the order of my arguments and my function wouldn't work. So I have to make...
public static float DistanceBetween(CoolCat cat1, Cat cat2)
{
return Mathf.Abs(cat1.tranform.position, cat1.position);
}
public static float DistanceBetween(ReallyCoolCat cat1, CoolCat cat2)
{
return Math.Abs(cat1.kittyVariables.position, cat2.transform.position);
}
// ... etc ...
So This means the amount of code per cute kitties I make grows by n^2. This amount of code growth is not acceptable due to how many cute kitties I want to make. I cannot implement inheritance because my cute kitties (though similar in name) have very different features and are unique. (I could add doggies and the such too.) So what I am thinking is to create an interface 'IDistanceable' that says the implementing class has a 'Position' property and implementing it in each kitty. But this starts to seem like overkill though, all I wanted was something that can rearrange my arguments and make Func(a,b) equal to Func(b,a)...
I don't really know what to do... both solutions (write 500 functions or make interface and lots of junk) both seem wrong.
The interface will NOT work due to the inability to modify some of the cute kitty classes...
Please help me and my cute kitties! Thanks!
If you can't modify the classes, you're best off wrapping them in something you can modify. That way, you can centralize the class-specific logic in one place (the different constructors).
class CatWrapper
{
private int position { get; set; }
public CatWrapper(Cat cat) { ... }
public CatWrapper(CoolCat cat) { ... }
public CatWrapper(ReallyCoolCat cat) { ... }
public DistanceFrom(CatWrapper other) { ... }
}
This is a purely academic answer, since #Andrews Pilser's is far superior for almost any real-world project, but this will solve it for any class that has any conceivable way of representing a location. It makes heavy use of lambda-expressions, and generics, and requires no control over the underlying classes.
The code was written in LINQPad, so it may look a little odd, but it is standard C# (version 7) that can be snapped right in to Visual Studio. File available here.
This uses a Dictionary to store a ToPointConverter for any Type that can be converted to a Point. A ToPointConverter is created from a static method Create that accepts a lambda that returns a Point from the specific generic T.
As you can see, I provide 3 example "kitty" classes that each store their location in completely different ways. The main function creates a converter for each, storing it in the dictionary of converters, and then calculates the distance between the different combination of "kitties". (I may have gotten my distance function wrong, it's late, but that is a minor detail.)
It produces this output:
2.23606797749979
9.05538513813742
2.23606797749979
8.06225774829855
9.05538513813742
8.06225774829855
void Main()
{
//Define conversion functions for anything that can be converted.
converters.Add(typeof(KittyA), ToPointConverter<KittyA>.Create(kitty => kitty.Location));
converters.Add(typeof(KittyB), ToPointConverter<KittyB>.Create(kitty => new Point { X = kitty.X, Y = kitty.Y }));
converters.Add(typeof(KittyC), ToPointConverter<KittyC>.Create(kitty => kitty.MyLocation));
//Declare some kitties
var kitty1 = new KittyA { Location = new Point { X = 1, Y = 1 } };
var kitty2 = new KittyB { X = 3, Y = 2 };
var kitty3 = new KittyC { MyLocation = new Point { X = 2, Y = 10 } };
//Calculate the distances
GetDistance(kitty1, kitty2).Dump();
GetDistance(kitty1, kitty3).Dump();
GetDistance(kitty2, kitty1).Dump();
GetDistance(kitty2, kitty3).Dump();
GetDistance(kitty3, kitty1).Dump();
GetDistance(kitty3, kitty2).Dump();
}
private Dictionary<Type, IToPointConverter> converters = new Dictionary<Type, IToPointConverter>();
//A helper function that does the converts the passed objects in to Points, and calculates the distance between them.
private double GetDistance(object obj1, object obj2)
{
var point1 = GetConvrterFor(obj1).Convert(obj1);
var point2 = GetConvrterFor(obj2).Convert(obj2);
return Math.Sqrt(Math.Pow(point2.X - point1.X, 2) + Math.Pow(point2.Y - point1.Y, 2));
}
//Another helper that gets the IToPointConverter for the object instance passed in.
private IToPointConverter GetConvrterFor(object obj) => converters[obj.GetType()];
//This generic class stores a lambda expression that converters from T to a Point
public class ToPointConverter<T> : IToPointConverter
{
public static ToPointConverter<T> Create(Func<T, Point> conversion)
{
return new ToPointConverter<T>(conversion);
}
private ToPointConverter(Func<T, Point> conversion)
{
_conversion = conversion;
}
private Func<T, Point> _conversion;
public Point Convert(T obj) => _conversion(obj);
Point IToPointConverter.Convert(object obj) => Convert((T)obj);
}
//The non-generic interface for the converter (so different closed generic types can be stored in the same dictionary, and have their Convert method called.)
public interface IToPointConverter
{
Point Convert(object obj);
}
//Just a standard structure to hold a location. You would use whatever native location class your framework has.
public struct Point
{
public int X;
public int Y;
}
//Some example kitty classes
public class KittyA
{
public Point Location { get; set; }
}
public class KittyB
{
public int X { get; set; }
public int Y { get; set; }
}
public class KittyC
{
public Point MyLocation { get; set; }
}
Say I have a class like this for calculating the cost of travelling different distances with different modes of transportation:
public class TransportationCostCalculator
{
public double DistanceToDestination { get; set; }
public decimal CostOfTravel(string transportMethod)
{
switch (transportMethod)
{
case "Bicycle":
return (decimal)(DistanceToDestination * 1);
case "Bus":
return (decimal)(DistanceToDestination * 2);
case "Car":
return (decimal)(DistanceToDestination * 3);
default:
throw new ArgumentOutOfRangeException();
}
}
This is fine and all, but switch cases can be a nightmare to maintenance wise, and what if I want to use airplane or train later on? Then I have to change the above class. What alternative to a switch case could I use here and any hints to how?
I'm imagining using it in a console application like this which would be run from the command-line with arguments for what kind of transportation vehicle you want to use, and the distance you want to travel:
class Program
{
static void Main(string[] args)
{
if(args.Length < 2)
{
Console.WriteLine("Not enough arguments to run this program");
Console.ReadLine();
}
else
{
var transportMethod = args[0];
var distance = args[1];
var calculator = new TransportCostCalculator { DistanceToDestination = double.Parse(distance) };
var result = calculator.CostOfTravel(transportMethod);
Console.WriteLine(result);
Console.ReadLine();
}
}
}
Any hints greatly appreciated!
You could do something like this:
public class TransportationCostCalculator {
Dictionary<string,double> _travelModifier;
TransportationCostCalculator()
{
_travelModifier = new Dictionary<string,double> ();
_travelModifier.Add("bicycle", 1);
_travelModifier.Add("bus", 2);
_travelModifier.Add("car", 3);
}
public decimal CostOfTravel(string transportationMethod) =>
(decimal) _travelModifier[transportationMethod] * DistanceToDestination;
}
You could then load the transportation type and it's modifier in a configuration file instead of using a switch statement. I put it in the constructor to show the example, but it could be loaded from anywhere. I would also probably make the Dictionary static and only load it once. There is no need to keep populating it each time you create a new TransportationCostCalculator especially if it isn't going to change during runtime.
As noted above, here is how you could load it by a configuration file:
void Main()
{
// By Hard coding.
/*
TransportationCostCalculator.AddTravelModifier("bicycle", 1);
TransportationCostCalculator.AddTravelModifier("bus", 2);
TransportationCostCalculator.AddTravelModifier("car", 3);
*/
//By File
//assuming file is: name,value
System.IO.File.ReadAllLines("C:\\temp\\modifiers.txt")
.ToList().ForEach(line =>
{
var parts = line.Split(',');
TransportationCostCalculator.AddTravelModifier
(parts[0], Double.Parse(parts[1]));
}
);
}
public class TransportationCostCalculator {
static Dictionary<string,double> _travelModifier =
new Dictionary<string,double> ();
public static void AddTravelModifier(string name, double modifier)
{
if (_travelModifier.ContainsKey(name))
{
throw new Exception($"{name} already exists in dictionary.");
}
_travelModifier.Add(name, modifier);
}
public double DistanceToDestination { get; set; }
TransportationCostCalculator()
{
_travelModifier = new Dictionary<string,double> ();
}
public decimal CostOfTravel(string transportationMethod) =>
(decimal)( _travelModifier[transportationMethod] * DistanceToDestination);
}
Edit: It was mentioned in the comments that this wouldn't allow the equation to be modified if it ever needed to change without updating the code, so I wrote up a post about how to do it here: https://kemiller2002.github.io/2016/03/07/Configuring-Logic.html.
It looks to me like any solution based on your current method is flawed in one critical way: No matter how you slice it, you're putting data in your code. This means every time you want to change any of these numbers, add a new vehicle type, etc., you have to edit code, and then recompile, distribute a patch, etc.
What you really should be doing is putting that data where it belongs - in a separate, non-compiled file. You can use XML, JSON, some form of database, or even just a simple config file. Encrypt it if you want, not necessarily needed.
Then you'd simply write a parser that reads the file and creates a map of vehicle type to cost multiplier or whatever other properties you want to save. Adding a new vehicle would be as simple as updating your data file. No need edit code or recompile, etc. Much more robust and easier to maintain if you plan to add stuff in the future.
Sounds like a good candidate for dependency-injection:
interface ITransportation {
decimal CalcCosts(double distance);
}
class Bus : ITransportation {
decimal CalcCosts(double distance) { return (decimal)(distance * 2); }
}
class Bicycle : ITransportation {
decimal CalcCosts(double distance) { return (decimal)(distance * 1); }
}
class Car: ITransportation {
decimal CalcCosts(double distance) { return (decimal)(distance * 3); }
}
Now you can easily create a new class Plane:
class Plane : ITransportation {
decimal CalcCosts(double distance) { return (decimal)(distance * 4); }
}
Now create a constrcutor for your calculator that expects an instance of ITransportation. Within your CostOfTravel-method you can now call ITransportation.CalcCosts(DistanceToDestination).
var calculator = new TransportationCostCalculator(new Plane());
This has the advantage that you can exchange your actual transportation-instance without any code-change to your TransportationCostCalculator-class.
To complete this design you might also create a TransportationFactory as follows:
class TransportationFactory {
ITransportation Create(string type) {
switch case "Bus": return new Bus(); break
// ...
}
Which you call like
ITransportation t = myFactory.Create("Bus");
TransportationCostCalculator calculator = new TransportationCostCalculator(t);
var result = myCalculator.CostOfTravel(50);
You could define an abstract class like this, and have each TransportationMethod extend the abstract class:
abstract class TransportationMethod {
public TransportationMethod() {
// constructor logic
}
abstract public double travelCost(double distance);
}
class Bicycle : TransportationMethod {
public Bicycle() : base() { }
override public double travelCost(double distance) {
return distance * 1;
}
}
class Bus : TransportationMethod {
public Bus() : base() { }
override public double travelCost(double distance) {
return distance * 2;
}
}
class Car : TransportationMethod {
public Car() : base() { }
override public double travelCost(double distance) {
return distance * 3;
}
}
So in your actual method call, it could be rewritten like this:
public decimal CostOfTravel(TransportationMethod t) {
return t.travelCost(DistanceToDestination);
}
You could use a strategy class for each type of travel. But, then you'd probably need a factory to create the strategy based upon the transport method which would likely have a switch statement to return the appropriate calculator.
public class CalculatorFactory {
public static ICalculator CreateCalculator(string transportType) {
switch (transportType) {
case "car":
return new CarCalculator();
...
public class CarCalculator : ICalculator {
public decimal Calc(double distance) {
return distance * 1;
}
}
....
You can make a Dictionary that returns a multiplier based on transport.
public class TransportationCostCalculator
{
Dictionary<string, int> multiplierDictionary;
TransportationCostCalculator ()
{
var multiplierDictionary= new Dictionary<string, int> ();
dictionary.Add ("Bicycle", 1);
dictionary.Add ("Bus", 2);
....
}
public decimal CostOfTravel(string transportMethod)
{
return (decimal) (multiplierDictionary[transportMethod] * DistanceToDestination);
}
I think the answer is some kind of database.
If you use some, the TransportCostCalculator ask the database for the multiplayer to the given transportmethod.
The database may be a text-file or an xml or an SQL-server. Simply a key-value-pair.
If you want to use code-only there is - tmo - no way to avoid the translation from transportmethod to multiplayer (or cost). So some kind of swicht is needed.
With the database you put the dictionary out of your code and you must not change your code to apply new transportmethods or change the values.
This is a case for the strategy design pattern. Create a base class, say TravelCostCalculator, then develop classes for each mode of travel you will consider, each overriding a common method, Calculate(double). You can then instantiate the specific TravelCostCalculator as needed using the factory pattern.
The trick is in how to construct the factory (without a switch statement). The way I do this is by having a static class constructor (public static Classname() - not an instance constructor) that registers each strategy class with the factory in a Dictionary<string, Type>.
Since C# does not run class constructors deterministically (like C++ does in most cases) you have to explicitly run them to ensure they will run. This could be done in the main program or in the factory constructor. The downside is that if you add a strategy class, you must also add it to the list of constructors to be run. You can either create a static method that must be run (Touch or Register) or you can also use System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor.
class Derived : Base
{
public static Derived()
{
Factory.Register(typeof(Derived));
}
}
// this could also be done with generics rather than Type class
class Factory
{
public static Register(Type t)
{
RegisteredTypes[t.Name] = t;
}
protected Dictionary<string, Type t> RegisteredTypes;
public static Base Instantiate(string typeName)
{
if (!RegisteredTypes.ContainsKey(typeName))
return null;
return (Base) Activator.CreateInstance(RegisteredTypes[typeName]);
}
}
I prefer to use Enum for that like this:
public enum TransportMethod
{
Bicycle = 1,
Bus = 2,
Car = 3
}
And use it like this method:
public decimal CostOfTravel(string transportMethod)
{
var tmValue = (int)Enum.Parse(typeof(TransportMethod), transportMethod);
return DistanceToDestination * tmValue;
}
Note that above method is case-sensitive, So you can capitalize first char;
Related Answer
It was said before but i want to give related topic another shot.
This is a good example for reflection.
"Reflection objects are used for obtaining type information at runtime. The classes that give access to the metadata of a running program are in the System.Reflection namespace."
By using reflection, you will avoid compiling code if another switch type such as train is wanted to add the program. You will solve the problem on the fly by using a config file.
I recently solved a similar problem with strategy patttern, by using dependency injection but I still end up with switch statement. It doesnt solve your problem this way. Method suggested by tyson still needs recompile if a new type added to dictionary.
An example of what i am talking about:
Dynamic Loading of Custom Configuration XML using Reflection in C# :
http://technico.qnownow.com/dynamic-loading-of-custom-configuration-xml-using-reflection-in-c/
Define a look up table array 3 by 2.
Look up rate value in array cell adjacent to transport type.
Calculate cost based on rate.
Quite often I come across the need for small immutable data structures. Others would probably use Tuples in these cases, but I really dislike that Tuples don't read nicely and don't express that much meaning. A Value2 of int doesn't tell me anything.
An example would be creating a lookup table (Dictionary) for a combination of two properties, i.e. Name and Rating.
The shortest way to make an immutable struct for these cases that I know of is this:
public struct Key
{
public string Name { get; private set; }
public int Rating { get; private set; }
public LolCat(string name, int rating) : this()
{
Name = name;
Rating = rating;
}
}
// useage
var key = new Key( "MonorailCat", 5 );
In my opinion there is still a lot of 'syntactic fat' in here that I would like to get rid of.
I could make it a lot more readable when I would just expose fields directly.
public struct Key
{
public string Name;
public int Rating;
}
// useage
var key = new Key { Name = "MonorailCat", Rating = 5 };
I really like the syntax of this, because there is barely any syntactic fat. The big disadvantage is of course that it is not immutable, with all it's dangers.
In the ideal case I would just like to have a special type for this, with the real bare minimum of definition, like:
public immutable struct Key
{
string Name;
int Rating;
}
// useage (needs compiler magic)
var key = new Key( Name: "MonorailCat", Rating: 5 );
Question
Is there a real world solution something closer to the example on the bottom, to reduce the amount of syntactic fat for a very simple immutable struct?
As of C# 6, you can write fairly compact struct initializers:
public struct Key
{
public string Name { get; }
public int Rating { get; }
public Key(string name, int rating)
{
this.Name = name;
this.Rating = rating;
}
}
... which is at least significantly shorter. I'd strongly advise implementing IEquatable<Key>, mind you.
Note that as you're dealing with a struct, you'll still be able to write:
Key key = new Key();
Console.WriteLine(key.Rating); // 0
... which may not be a problem, but generally needs considering at least.
Before C# 6, I'd actually go even longer than your current code, in order to write the properties as read-only properties:
public struct Key
{
private readonly string name;
private readonly int rating;
public string Name { get { return name; } }
public int Rating { get { return rating; } }
public Key(string name, int rating)
{
this.name = name;
this.rating = rating;
}
}
I feel this makes it more clearly "meant to be immutable" - if you've got a writable property, even if the setter is only private, that doesn't convey the right impression IMO. (Although it's worth noting that immutability in structs is always a little bit of a pretense, given that you can assign to this in members...)
AFAIK, the shortest you can write is using readonly, which is hardly shorter than your struct using properties:
public struct Key
{
public readonly string Name;
public readonly int Rating;
public Key(string name, int rating){
Name = name;
Rating = rating;
}
}
var key = new Key("MonorailCat", 5);
In C# 7.2 there is a readonly struct.
readonly public struct ReadonlyPoint3D
{
public ReadonlyPoint3D(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
//setters would not compile
public double X { get; }
public double Y { get; }
public double Z { get; }
private static ReadonlyPoint3D origin = new ReadonlyPoint3D();
public static ref readonly ReadonlyPoint3D Origin => ref origin;
public ReadonlyPoint3D Scale(double factor)
{
/* all fail compilation
X *= factor;
Y *= factor;
Z *= factor;
*/
return new ReadonlyPoint3D(X * factor, Y * factor, Z * factor);
}
}
The compiler enforces that all members are readonly.
This passed as 'in' reference rather than copy of receiver which is usually more efficient.
Reference