Alternative to assignment operator overloading - c#

Let me start off by stating that I know the assignment operator in C# cannot be overloaded/overridden. However, if I have a class like so:
public class Time
{
private int Hour, Minute;
public int minutes;
public Time(int m)
{
this.minutes = m;
this.Hour = m / 60;
this.Minute = m % 60;
}
public Time(int hh, int mm)
{
this.minutes = 60 * hh + mm;
this.Hour = hh;
this.Minute = mm;
}
public static explicit operator Time(int i1)
{
return new Time(i1);
}
}
Two things:
1) Is the explicit conversion overload at the bottom necessary?
2) I want to do
Time newTime = 510;
and have Hour and Minute reflect the new minutes. Without making another object, is the only way to make a function like so:
public void changeminutes(int m)
{
this.minutes = m;
this.Hour = m / 60;
this.Minute = m % 60;
}
and do this:
Time newTime = new Time();
newTime.changeminutes(510);
edit:
I probably should have mentioned that I'm still in learning C#. A lot of your suggestions are flying over my head. Sorry.
next edit :
This isn't necessarily about time. I just used it to illustrate my example.

You can create an implicit cast from int to Time.
However, I recommend against it.
Unless they're between equivalent types (eg, int and long), implicit casts will end up creating lots of confusion.
In addition, it isn't obvious that that should mean minutes and not seconds.
You can create a much nicer syntax using extension methods:
Time t = 510.Minutes();

It looks like you're trying to make a reference type behave like a value type, which is... um, tricky. If you really don't want to use the constructor for this (and explaining why that is might help us answer), you can use a static "factory" method:
public static Time FromMinutes(int m)
{
return new Time(m);
}
And use it like this:
var t = Time.FromMinutes(510);
This is similar to what the TimeSpan class lets you do.

For you case an implicit conversion would work but...
Conversions are not to be used when you loose data, or even semantics like in this case. You know that the number will become a Time, but you don't know which unit of time will the number be converted into.
If somebody is going to read the code it will not have any clue what the number represents without looking at the internal definition of the Time class. Think if that was in an outside project. Debugging hell? :)

First, you want to use implicit casting to achieve Time x = 123;, but as others are pointing out it's probably a poor design choice because it's not immediately clear what the number represents (and most people would assume a Unix timestamp).
Second, why not use the Minutes property to set minutes, and simply convert the value into the proper value, while changing Hours?
time.Minutes = 510;
// in class def:
public int Minutes
{
get { return minutes; }
set
{
hours = value / 60;
minutes = value % 60;
}
}

Related

Passing enumerated values to functions

Say I have a function that takes an integer as an argument. I'd like to be able to use an enumerated list as a way to keep the integer values organized.
For example, I'd ideally like to be able to define these (pseudocode):
public enum days
{
monday,
tuesday,
etc...
}
public enum months
{
january,
february,
etc...
}
int doSomething(enum x)
{
return x + 1;
}
and then be able to call the function using either of the enumerated lists like this:
int a = doSomething(days.monday);
int y = doSomething(months.february);
This obviously won't work as-is because doSomething needs to be defined using just one of the enumerations (i.e. either days or months). I know of a couple of options. One is to simply cast to an int:
int a = doSomething((int)days.monday);
int y = doSomething((int)months.february);
The only problem with this is that this function gets called MANY places in my code, and it's clumsy to have to keep putting "(int)"s all over the place (one of the main motivations for grouping these int values together into enums in the first place is to make the code more readable).
Another option is to avoid enums altogether, and instead bundle the values into a container class, something like:
static class Days
{
static int x = 0;
static int monday = x++;
static int tuesday = x++;
}
Again, this will work but just seems awfully cumbersome when I have a lot of these container classes to define.
The answer might very well be that there is no simpler way, and that I need to be a grown-up and just accept one of these options. But I thought I would get a sanity check on that before committing to it. Is there a third option?
What is your issue?
public enum Days : short
{
Monday = 1,
Tuesday = 2,
...
}
DoSomething(Days.Monday);
void DoSomething(Days day)
{
Days nextDay = day + 1;
}
Also note already built-in enum System.DayOfWeek.
I got OP's point but afaik this is not supported by C# yet:
void DoSomething<T>(T e) where T : enum
{
T next = e + 1;
}
Any problem with System.DateTime?
This would be the most pragmatic type to use.
You could overload your method, if you really just want the int value, perhaps something like this?
int dosomething(enum x)
{return dosomething((int)x)}
int dosomething(int x)
{return x+1}
yes you can do so
public enum days : int
{
monday,
tuesday,
...
}
automatically monday becomes 0 and tuesday becomes 1 and so on
public enum months : int
{
january,
february,
...
}
same for months
int doSomething(Enum x)
{
return (int)x + 1;
}
and call it as
int a = doSomething(days.monday);
or call it as
int a = doSomething(months.january);
now days.monday equals 0 and after method a becomes 1.
Or if you don't want to change all existing Enums:
public static int DoSomething(Enum x)
{
int xInt = (int)Convert.ChangeType(x, x.GetTypeCode());
DoSomething(xInt);
}
as stated here: enums-returning-int-value
public enum days : int
{ monday, tuesday,
}
public enum months :int
{ january, february, march,
}
public int doSomething(int z)
{
return z + 1;
}
// your calling method int c = ee.doSomething((int)testenums.months.march); int c = ee.doSomething((int)testenums.day.February);
working code as you always pass enum and which is of type int you just need to parse and send this code perfectly works.. let me know
DId you try to overload a function by parameter:
int DoSomething(Enum1 value)
int DoSomething(Enum2 value)
I spent a “little” time on this, because got a same problem(solution).
So here is my solution which work fine on (.NET 4), Windows Forms:
VB:NET
Private Function DoSomething(Of TEnum As {IComparable, IConvertible, IFormattable})(ByVal valueEnum As TEnum) As Int32
Dim i As Int32 = CInt(Convert.ChangeType(valueEnum, valueEnum.GetTypeCode()))
//Do something with int
i += 1
Return i
End Function
C#
private int DoSomething<TEnum>(TEnum valueEnum) where TEnum: IComparable, IConvertible, IFormattable
{
int i = 0;
i = (int)Convert.ChangeType(valueEnum, valueEnum.GetTypeCode());
i++;
return i;
}

What is the best way to calculate a formula when using an int as a divisor

Often I find myself having a expression where a division by int is a part of a large formula. I will give you a simple example that illustrate this problem:
int a = 2;
int b = 4;
int c = 5;
int d = a * (b / c);
In this case, d equals 0 as expected, but I would like this to be 1 since 4/5 multiplied by 2 is 1 3/5 and when converted to int get's "rounded" to 1. So I find myself having to cast c to double, and then since that makes the expression a double also, casting the entire expression to int. This code looks like this:
int a = 2;
int b = 4;
int c = 5;
int d = (int)(a * (b / (double)c));
In this small example it's not that bad, but in a big formula this get's quite messy.
Also, I guess that casting will take a (small) hit on performance.
So my question is basically if there is any better approach to this than casting both divisor and result.
I know that in this example, changing a*(b/c) to (a*b)/c would solve the problem, but in larger real-life scenarios, making this change will not be possible.
EDIT (added a case from an existing program):
In this case I'm caclulating the position of a scrollbar according to the size of the scrollbar, and the size of it's container. So if there is double the elements to fit on the page, the scrollbar will be half the height of the container, and if we have scrolled through half of the elements possible, that means that the scroller position should be moved 1/4 down so it will reside in the middle of the container. The calculations work as they should, and it displays fine. I just don't like how the expression looks in my code.
The important parts of the code is put and appended here:
int scrollerheight = (menusize.Height * menusize.Height) / originalheight;
int maxofset = originalheight - menusize.Height;
int scrollerposition = (int)((menusize.Height - scrollerheight) * (_overlayofset / (double)maxofset));
originalheight here is the height of all elements, so in the case described above, this will be the double of menusize.Height.
Disclaimer: I typed all this out, and then I thought, Should I even post this? I mean, it's a pretty bad idea and therefore doesn't really help the OP... In the end I figured, hey, I already typed it all out; I might as well go ahead and click "Post Your Answer." Even though it's a "bad" idea, it's kind of interesting (to me, anyway). So maybe you'll benefit in some strange way by reading it.
For some reason I have a suspicion the above disclaimer's not going to protect me from downvotes, though...
Here's a totally crazy idea.
I would actually not recommend putting this into any sort of production environment, at all, because I literally thought of it just now, which means I haven't really thought it through completely, and I'm sure there are about a billion problems with it. It's just an idea.
But the basic concept is to create a type that can be used for arithmetic expressions, internally using a double for every term in the expression, only to be evaluated as the desired type (in this case: int) at the end.
You'd start with a type like this:
// Probably you'd make this implement IEquatable<Term>, IEquatable<double>, etc.
// Probably you'd also give it a more descriptive, less ambiguous name.
// Probably you also just flat-out wouldn't use it at all.
struct Term
{
readonly double _value;
internal Term(double value)
{
_value = value;
}
public override bool Equals(object obj)
{
// You would want to override this, of course...
}
public override int GetHashCode()
{
// ...as well as this...
return _value.GetHashCode();
}
public override string ToString()
{
// ...as well as this.
return _value.ToString();
}
}
Then you'd define implicit conversions to/from double and the type(s) you want to support (again: int). Like this:
public static implicit operator Term(int x)
{
return new Term((double)x);
}
public static implicit operator int(Term x)
{
return (int)x._value;
}
// ...and so on.
Next, define the operations themselves: Plus, Minus, etc. In the case of your example code, we'd need Times (for *) and DividedBy (for /):
public Term Times(Term multiplier)
{
// This would work because you would've defined an implicit conversion
// from double to Term.
return _value * multiplier._value;
}
public Term DividedBy(Term divisor)
{
// Same as above.
return _value / divisor._value;
}
Lastly, write a static helper class to enable you to perform Term-based operations on whatever types you want to work with (probably just int for starters):
public static class TermHelper
{
public static Term Times(this int number, Term multiplier)
{
return ((Term)number).Times(multiplier);
}
public static Term DividedBy(this int number, Term divisor)
{
return ((Term)number).DividedBy(divisor);
}
}
What would all of this buy you? Practically nothing! But it would clean up your expressions, hiding away all those unsightly explicit casts, making your code significantly more attractive and considerably more impossible to debug. (Once again, this is not an endorsement, just a crazy-ass idea.)
So instead of this:
int d = (int)(a * (b / (double)c)); // Output: 2
You'd have this:
int d = a.Times(b.DividedBy(c)); // Output: 2
Is it worth it?
Well, if having to write casting operations were the worst thing in the world, like, even worse than relying on code that's too clever for its own good, then maybe a solution like this would be worth pursuing.
Since the above is clearly not true... the answer is a pretty emphatic NO. But I just thought I'd share this idea anyway, to show that such a thing is (maybe) possible.
First of all, C# truncates the result of int division, and when casting to int. There's no rounding.
There's no way to do b / c first without any conversions.
Multiply b times 100. Then divide by 100 at the end.
In this case, I would suggest Using double instead, because you don't need 'exact' precision.
However, if you really feel you want to do it all without floating-point operation, I would suggest creating some kind of fraction class, which is far more complex and less efficient but you can keep track of all dividend and divisor and then calculate it all at once.

Does C# support multiple return values?

This is a very basic question, and if what I am thinking of doing is complicated/involved, then I don't expect you to go into detail... I've read that this may involve structs or hash or some other scary procedure I've not gotten to yet. If so, I'm sure it'll get me soon.
Working on learning classes, methods, and return values.
I'd like to have my class/method return Current Hour and Minute. Simple enough, really.
Is this constructed correctly, or properly?
class MyClass
{
public int GetHour (int hr, int min)
{
DateTime dt = DateTime.Now;
int hour = dt.Hour;
int minute = dt.Minute;
return hour;
return minute;
}
}
And, calling it from Main(): Getting some errors (No overload for method and Unreachable code detected)
static void Main ( string[] args )
{
MyClass mc = new MyClass ();
Console.WriteLine ("Hour: {0} \n Minute: {1}", mc.GetHour());
Console.ReadLine ();
}
Question is: Am I Close?
As mentioned by #ChaosPandion, in that specific case you would return a DateTime struct.
In general, however, you would have the following options:
Using out parameters
This is a simple way that will usually always work. However, it is a bit clunky, as the result is returned where you usually would expect the function arguments to be passed and the method signature might get lengthy and hard to refactor.
public void GetTime(out int hr, out int min)
{
DateTime dt = DateTime.Now;
hr = dt.Hour;
min = dt.Minute;
}
static void Main(string[] args)
{
// declare variables for out parameters first
int hour, minute;
GetTime(out hour, out minute);
}
Using an array
This is a simple method that works well if the values to be returned have the same type.
public int[] GetTime()
{
DateTime dt = DateTime.Now;
return new[] { dt.Hour, dt.Minute};
}
Using a property bag (A property bag is a simple class which only has properties)
This is very convenient and allows easy modification of the type and number of returned values later on without changing the method signature.
class A
{
int Prop1 { get; set; }
int Prop2 { get; set; }
}
public A SomeMethod()
{
return new A() { Prop1 = 1, Prop2 = 2 }
}
Using a Tuple
In C# 4.0 (requires VS 2010) you can use the Tuple<T1, T2, ...> class:
public Tuple<int, int> GetTime()
{
DateTime dt = DateTime.Now;
return Tuple.Create(dt.Hour, dt.Minute);
}
C# 7.0 Tuples
C# 7.0 adds support for multiple return values. You can write code like this to return an implicitly created tuple:
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
The tuple elements are names Item1, Item2, etc by default, but you can also specify names, e.g.
(string first, string middle, string last) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
and then access the tuple elements via those names:
var names = LookupName(id);
WriteLine($"found {names.first} {names.last}.");
C# does not support multiple return values so in this case you should return a DateTime struct which is the idiomatic approach. The client code can simply ignore the properties that they don't care about. You could create your own simple struct but it really isn't worth the effort.
C# doesn't support the idea of directly returning multiple values from a method in that fashion. However there are a couple of ways to create methods which return multiple values. The first is to use ref / out parameters.
public void GetHourMinute(out int hour, out int minute) {
var now = DateTime.Now;
hour = now.Hour;
minute = now.Minute;
}
The second is to create a wrapper type which encapsulates the two values. Starting in 4.0 this can be made a bit easier by using the Tuple type.
public Tuple<int,int> GetHourMinute() {
var now = DateTime.Now;
return Tuple.Create(now.Hour, now.Minute);
}
I suggest you return the DateTime object. Then in your main method you call Hour and Minute properties.
1: You can't have two returns. Once the compiler reaches the return statement, the operation of the method is finished.
2: Why would you want your method to receive parameters if you don't use them? DateTime.Now gives you the current time, if you'll think of yourself as that method - what do you need in order to complete your task? Nothing.
So, practical tips:
1. Actually, the DateTime does what you need better than your method.
Console.WriteLine ("Hour: {0} \n Minute: {1}", DateTime.Now.Hour,DateTime.Now.Minute);
Would have been better,
but let's ignore that and consider it an exercise in classes.
2 Returning two values is against the concept of a method - a method returns one thing (there are exceptions as out ref, but we'll ignore them).
You can actually see that in your own code - your method name is GetHour not GetHourAndMinutes. I don't think I've ever seen a method's name with the word "and" - a method does only one thing.
Yeah, you can only return one 'thing' from method in C#.
The other problem you have is you are calling a method without any parameters. The things in the brackets:
public int GetHour (int hr, int min) // here
{
}
Are parameters. And you need to specify them when calling the method, like so:
mc.GetHour(1, 2);
But of course, in your case, it doesn't make sense to do this.
To answer the general question of: "How do I return more than one thing?" You encapsulate it in a class, set the properties, and return that class. It so happens, in the example you've given, the DateTime class does just that.
Hope this is helpful.
You cant return multiple value. TimeSpan is exactly what you are looking for. Create an object of that with hour, minute and even second that you want to capture and return it.
Come to think about it, for what you need above, you dont even have to write the method above. Just use DateTime.Now.TimeOfDay directly in your code
Sorry, you can't do that. You'd be better served returning an array or an object. You could return the DateTime object and use it.
Also as stated, your function signature wasn't being called properly.
class MyClass
{
public int[] GetHour ()
{
DateTime dt = DateTime.Now;
int hour = dt.Hour;
int minute = dt.Minute;
return new int[]{hour, minute};
}
}
static void Main ( string[] args )
{
MyClass mc = new MyClass ();
int[] temp = mc.GetHour();
Console.WriteLine ("Hour: {0} \n Minute: {1}", temp[0], temp[1]);
Console.ReadLine ();
}
In C# a method can return multiple times, if you use yield return format.
using System.Collections.Generic;
namespace YieldReturn
{
class Program
{
public static void Main(string[] args)
{
MyClass mc = new MyClass();
IEnumerator<int> enu = mc.GetHour().GetEnumerator();
enu.MoveNext();
int hour = enu.Current;
enu.MoveNext();
int min = enu.Current;
Console.WriteLine("Hour {0} min {1}", hour, min);
Console.ReadKey(true);
}
}
class MyClass
{
DateTime dt;
public MyClass()
{
dt = DateTime.Now;
}
public IEnumerable<int> GetHour()
{
int hour = dt.Hour;
int minute = dt.Minute;
yield return hour;
yield return minute;
}
}
}
Gives "Hour 8 min 50"
You can't return twice, only once.
Several return values at once require lambda expressions, and AFAIK, only Python is capable of that.
Syntax there goes like this:
return x, y
So maybe you should try IronPython, and then decompile to C#.
In C#, there are exactly two ways to return more than one value:
1. Use arguments as call by reference, that way you can assign 3 variables and then return.
2. Use some kind of struct/class/array/tuple/vector and place your multiple values into it.
Call by reference is something like this:
public static void xxx(ref var1, ref
var2, ref var3) {
var1 = 123;
var2 = 456;
var3 = 789;
return; }
then you do:
int a =1;
int b=2;
int c=3;
xxx(ref a, ref b, ref c);
Console.WriteLine(a.ToString());
Console.WriteLine(b.ToString());
Console.WriteLine(c.ToString());
The question I would like to ask you is why do you want to return multiple values? Returning multiple values for me means having multiple responsibilities in the function and that should be a big don't since it is violating SRP. But, if those return values are related maybe they make an object that you're missing and should be created instead? Or a list with one type of object.
So for short. Why? Encapsulate your return values in ONE object? Don't do multiple things in one function.
EDIT: In your case I wouldn't even wrap your functionality in a function just write:
static void Main ( string[] args )
{
MyClass mc = new MyClass ();
DateTime now = DateTime.Now;
int hour = now.Hour;
int min = now.Minute;
Console.WriteLine ("Hour: {0} \n Minute: {1}", hour, min);
Console.ReadLine ();
}
And your function name GetHour doesn't do what the function says... if it says GetHour it should return the hour and not the hour plus the minute.

How to implement Year for movies in C#?

I am writing a Movie class that will have a Year property. Should it be just an int, or should I use a DateTime object?
Just wondering the best option. Maybe I am missing something.
I would probably use an int for simplicity, and make sure that in the setter you verify that the year value makes sense.
Alternatively, you can create a type to just represents years - this would make sure you don't misuse the year as a regular integral value. This gets complicated though, especially if you want to start overloading operators to support year addition and subtraction. Unless you really need this extra level of type safety, I would stick with an int.
If it's only going to be a year value, then int will be simpler. You could also consider just saving the release date as a DateTime, and get the year from that (instead of having a year attribute).
If it's only ever going to be the year then an int (or custom type) would do.
If you want to store the month as well then I'd use a DateTime.
The Agile mantra - YAGNI (You Ain't Gonna Need It) - would suggest an int until you want more information and then refactor into a DateTime then.
use datetime object you can get the year from it like .year well....
Well, DateTime has the unfortunate side-effect of specifying both a data and a time and not only some subsets. Ideally you would probably want some "time" object with varying levels of accuracy, as needed. But for this I'd suggest using an int since you are modeling exactly a year, not a complete date.
I would create a custom type, (a struct) to hold this value.
public struct FilmYear
{
private int yr;
private bool isDef;
public bool HasValue { return isDef; }
public bool IsNull { return !HasValue; }
private FilmYear(int year) { yr = year; isDef = true; }
public static FilmYear ThisYear = new FilmYear(DateTime.Today.Year);
public static FilmYear LastYear = new FilmYear(DateTime.Today.Year - 1);
public static FilmYear NextYear = new FilmYear(DateTime.Today.Year + 1);
public static FilmYear Parse(DateTime anyDateInYear)
{ return new FilmYear(anyDateInYear.Year); }
public static FilmYear Parse(int year)
{ return new FilmYear(year); }
public static FilmYear Parse(string year)
{ return new FilmYear(Int32.parse(year)); }
public overide string ToString()
{ return yr.ToString(); }
//etc... you can add:
// - operator overloads to add subtract years to the value,
// - conversion operator overloads to implicitly/(or explicitly)
// convert datetimes to FilmYears, as appropriate
// - overload equality and comparison operators ...
}
Usage
FilmYear avatarYear = FilmYear.ThisYear;
FilmYear casablancaYear = FilmYear.Parse(1943);
If this is for casual users, an int (or class based on int) is correct.
If you are doing a 'real' filmography, you'll need both an int and a string: the int for sorting and searching, with the string containing the "truth" of cases where the data is incomplete or tentative ("1958?").
This is also why you shouldn't use a Date or DateTime: there's no way to distinguish between "1/1/1958" and "sometime in 1958".
I think to properly answer that question, you need to supply a little more context. For what kind of application? Is this information going to be stored in a database? What kinds of queries do you expect users to perform against the data? Things like that.
If you're only looking to keep track of the Year, then keep it a int. If you're tracking the release date/production date, then use DateTime
For simplicity using an int is the most direct option; if there are any special methods for the data then creating a Year type and encapsulating all behaviors would be a clean and simple solution--if you go that route you can store the value as either an int or DateTime and offer .ToInt(), .ToDateTime(), methods and others to handle all use-cases.

Units of measure in C# - almost

Inspired by Units of Measure in F#, and despite asserting (here) that you couldn't do it in C#, I had an idea the other day which I've been playing around with.
namespace UnitsOfMeasure
{
public interface IUnit { }
public static class Length
{
public interface ILength : IUnit { }
public class m : ILength { }
public class mm : ILength { }
public class ft : ILength { }
}
public class Mass
{
public interface IMass : IUnit { }
public class kg : IMass { }
public class g : IMass { }
public class lb : IMass { }
}
public class UnitDouble<T> where T : IUnit
{
public readonly double Value;
public UnitDouble(double value)
{
Value = value;
}
public static UnitDouble<T> operator +(UnitDouble<T> first, UnitDouble<T> second)
{
return new UnitDouble<T>(first.Value + second.Value);
}
//TODO: minus operator/equality
}
}
Example usage:
var a = new UnitDouble<Length.m>(3.1);
var b = new UnitDouble<Length.m>(4.9);
var d = new UnitDouble<Mass.kg>(3.4);
Console.WriteLine((a + b).Value);
//Console.WriteLine((a + c).Value); <-- Compiler says no
The next step is trying to implement conversions (snippet):
public interface IUnit { double toBase { get; } }
public static class Length
{
public interface ILength : IUnit { }
public class m : ILength { public double toBase { get { return 1.0;} } }
public class mm : ILength { public double toBase { get { return 1000.0; } } }
public class ft : ILength { public double toBase { get { return 0.3048; } } }
public static UnitDouble<R> Convert<T, R>(UnitDouble<T> input) where T : ILength, new() where R : ILength, new()
{
double mult = (new T() as IUnit).toBase;
double div = (new R() as IUnit).toBase;
return new UnitDouble<R>(input.Value * mult / div);
}
}
(I would have liked to avoid instantiating objects by using static, but as we all know you can't declare a static method in an interface)
You can then do this:
var e = Length.Convert<Length.mm, Length.m>(c);
var f = Length.Convert<Length.mm, Mass.kg>(d); <-- but not this
Obviously, there is a gaping hole in this, compared to F# Units of measure (I'll let you work it out).
Oh, the question is: what do you think of this? Is it worth using? Has someone else already done better?
UPDATE for people interested in this subject area, here is a link to a paper from 1997 discussing a different kind of solution (not specifically for C#)
You are missing dimensional analysis. For example (from the answer you linked to), in F# you can do this:
let g = 9.8<m/s^2>
and it will generate a new unit of acceleration, derived from meters and seconds (you can actually do the same thing in C++ using templates).
In C#, it is possible to do dimensional analysis at runtime, but it adds overhead and doesn't give you the benefit of compile-time checking. As far as I know there's no way to do full compile-time units in C#.
Whether it's worth doing depends on the application of course, but for many scientific applications, it's definitely a good idea. I don't know of any existing libraries for .NET, but they probably exist.
If you are interested in how to do it at runtime, the idea is that each value has a scalar value and integers representing the power of each basic unit.
class Unit
{
double scalar;
int kg;
int m;
int s;
// ... for each basic unit
public Unit(double scalar, int kg, int m, int s)
{
this.scalar = scalar;
this.kg = kg;
this.m = m;
this.s = s;
...
}
// For addition/subtraction, exponents must match
public static Unit operator +(Unit first, Unit second)
{
if (UnitsAreCompatible(first, second))
{
return new Unit(
first.scalar + second.scalar,
first.kg,
first.m,
first.s,
...
);
}
else
{
throw new Exception("Units must match for addition");
}
}
// For multiplication/division, add/subtract the exponents
public static Unit operator *(Unit first, Unit second)
{
return new Unit(
first.scalar * second.scalar,
first.kg + second.kg,
first.m + second.m,
first.s + second.s,
...
);
}
public static bool UnitsAreCompatible(Unit first, Unit second)
{
return
first.kg == second.kg &&
first.m == second.m &&
first.s == second.s
...;
}
}
If you don't allow the user to change the value of the units (a good idea anyways), you could add subclasses for common units:
class Speed : Unit
{
public Speed(double x) : base(x, 0, 1, -1, ...); // m/s => m^1 * s^-1
{
}
}
class Acceleration : Unit
{
public Acceleration(double x) : base(x, 0, 1, -2, ...); // m/s^2 => m^1 * s^-2
{
}
}
You could also define more specific operators on the derived types to avoid checking for compatible units on common types.
Using separate classes for different units of the same measure (e.g., cm, mm, and ft for Length) seems kind of weird. Based on the .NET Framework's DateTime and TimeSpan classes, I would expect something like this:
Length length = Length.FromMillimeters(n1);
decimal lengthInFeet = length.Feet;
Length length2 = length.AddFeet(n2);
Length length3 = length + Length.FromMeters(n3);
You could add extension methods on numeric types to generate measures. It'd feel a bit DSL-like:
var mass = 1.Kilogram();
var length = (1.2).Kilometres();
It's not really .NET convention and might not be the most discoverable feature, so perhaps you'd add them in a devoted namespace for people who like them, as well as offering more conventional construction methods.
I recently released Units.NET on GitHub and on NuGet.
It gives you all the common units and conversions. It is light-weight, unit tested and supports PCL.
Example conversions:
Length meter = Length.FromMeters(1);
double cm = meter.Centimeters; // 100
double yards = meter.Yards; // 1.09361
double feet = meter.Feet; // 3.28084
double inches = meter.Inches; // 39.3701
Now such a C# library exists:
http://www.codeproject.com/Articles/413750/Units-of-Measure-Validator-for-Csharp
It has almost the same features as F#'s unit compile time validation, but for C#.
The core is a MSBuild task, which parses the code and looking for validations.
The unit information are stored in comments and attributes.
Here's my concern with creating units in C#/VB. Please correct me if you think I'm wrong. Most implementations I've read about seem to involve creating a structure that pieces together a value (int or double) with a unit. Then you try to define basic functions (+-*/,etc) for these structures that take into account unit conversions and consistency.
I find the idea very attractive, but every time I balk at what a huge step for a project this appears to be. It looks like an all-or-nothing deal. You probably wouldn't just change a few numbers into units; the whole point is that all data inside a project is appropriately labeled with a unit to avoid any ambiguity. This means saying goodbye to using ordinary doubles and ints, every variable is now defined as a "Unit" or "Length" or "Meters", etc. Do people really do this on a large scale? So even if you have a large array, every element should be marked with a unit. This will obviously have both size and performance ramifications.
Despite all the cleverness in trying to push the unit logic into the background, some cumbersome notation seems inevitable with C#. F# does some behind-the-scenes magic that better reduces the annoyance factor of the unit logic.
Also, how successfully can we make the compiler treat a unit just like an ordinary double when we so desire, w/o using CType or ".Value" or any additional notation? Such as with nullables, the code knows to treat a double? just like a double (of course if your double? is null then you get an error).
Thanks for the idea. I have implemented units in C# many different ways there always seems to be a catch. Now I can try one more time using the ideas discussed above. My goal is to be able to define new units based on existing ones like
Unit lbf = 4.44822162*N;
Unit fps = feet/sec;
Unit hp = 550*lbf*fps
and for the program to figure out the proper dimensions, scaling and symbol to use. In the end I need to build a basic algebra system that can convert things like (m/s)*(m*s)=m^2 and try to express the result based on existing units defined.
Also a requirement must be to be able to serialize the units in a way that new units do not need to be coded, but just declared in a XML file like this:
<DefinedUnits>
<DirectUnits>
<!-- Base Units -->
<DirectUnit Symbol="kg" Scale="1" Dims="(1,0,0,0,0)" />
<DirectUnit Symbol="m" Scale="1" Dims="(0,1,0,0,0)" />
<DirectUnit Symbol="s" Scale="1" Dims="(0,0,1,0,0)" />
...
<!-- Derived Units -->
<DirectUnit Symbol="N" Scale="1" Dims="(1,1,-2,0,0)" />
<DirectUnit Symbol="R" Scale="1.8" Dims="(0,0,0,0,1)" />
...
</DirectUnits>
<IndirectUnits>
<!-- Composite Units -->
<IndirectUnit Symbol="m/s" Scale="1" Lhs="m" Op="Divide" Rhs="s"/>
<IndirectUnit Symbol="km/h" Scale="1" Lhs="km" Op="Divide" Rhs="hr"/>
...
<IndirectUnit Symbol="hp" Scale="550.0" Lhs="lbf" Op="Multiply" Rhs="fps"/>
</IndirectUnits>
</DefinedUnits>
there is jscience: http://jscience.org/, and here is a groovy dsl for units: http://groovy.dzone.com/news/domain-specific-language-unit-. iirc, c# has closures, so you should be able to cobble something up.
Why not use CodeDom to generate all possible permutations of the units automatically? I know it's not the best - but I will definitely work!
you could use QuantitySystem instead of implementing it by your own. It builds on F# and drastically improves unit handling in F#. It's the best implementation I found so far and can be used in C# projects.
http://quantitysystem.codeplex.com
Is it worth using?
Yes. If I have "a number" in front of me, I want to know what that is. Any time of the day. Besides, that's what we usually do. We organize data into a meaningful entity -class, struct, you name it. Doubles into coordinates, strings into names and address etc. Why units should be any different?
Has someone else already done better?
Depends on how one defines "better". There are some libraries out there but I haven't tried them so I don't have an opinion. Besides it spoils the fun of trying it myself :)
Now about the implementation. I would like to start with the obvious: it's futile to try replicate the [<Measure>] system of F# in C#. Why? Because once F# allows you to use / ^ (or anything else for that matter) directly on another type, the game is lost. Good luck doing that in C# on a struct or class. The level of metaprogramming required for such a task does not exist and I'm afraid it is not going to be added any time soon -in my opinion. That's why you lack the dimensional analysis that Matthew Crumley mentioned in his answer.
Let's take the example from fsharpforfunandprofit.com: you have Newtons defined as [<Measure>] type N = kg m/sec^2. Now you have the square function that that the author created that will return a N^2 which sounds "wrong", absurd and useless. Unless you want to perform arithmetic operations where at some point during the evaluation process, you might get something "meaningless" until you multiply it with some other unit and you get a meaningful result. Or even worse, you might want to use constants. For example the gas constant R which is 8.31446261815324 J /(K mol). If you define the appropriate units, then F# is ready to consume the R constant. C# is not. You need to specify another type just for that and still you won't be able to do any operation you want on that constant.
That doesn't mean that you shouldn't try. I did and I am quite happy with the results. I started SharpConvert around 3 years ago, after I got inspired by this very question. The trigger was this story: once I had to fix a nasty bug for the RADAR simulator that I develop: an aircraft was plunging in the earth instead of following the predefined glide path. That didn't make me happy as you could guess and after 2 hours of debugging, I realized that somewhere in my calculations, I was treating kilometers as nautical miles. Until that point I was like "oh well I will just be 'careful'" which is at least naive for any non trivial task.
In your code there would be a couple of things I would do different.
First I would turn UnitDouble<T> and IUnit implementations into structs. A unit is just that, a number and if you want them to be treated like numbers, a struct is a more appropriate approach.
Then I would avoid the new T() in the methods. It does not invoke the constructor, it uses Activator.CreateInstance<T>() and for number crunching it will be bad as it will add overhead. That depends though on the implementation, for a simple units converter application it won't harm. For time critical context avoid like the plague. And don't take me wrong, I used it myself as I didn't know better and I run some simple benchmarks the other day and such a call might double the execution time -at least in my case. More details in Dissecting the new() constraint in C#: a perfect example of a leaky abstraction
I would also change Convert<T, R>() and make it a member function. I prefer writing
var c = new Unit<Length.mm>(123);
var e = c.Convert<Length.m>();
rather than
var e = Length.Convert<Length.mm, Length.m>(c);
Last but not least I would use specific unit "shells" for each physical quantity (length time etc) instead of the UnitDouble, as it will be easier to add physical quantity specific functions and operator overloads. It will also allow you to create a Speed<TLength, TTime> shell instead of another Unit<T1, T2> or even Unit<T1, T2, T3> class. So it would look like that:
public readonly struct Length<T> where T : struct, ILength
{
private static readonly double SiFactor = new T().ToSiFactor;
public Length(double value)
{
if (value < 0) throw new ArgumentException(nameof(value));
Value = value;
}
public double Value { get; }
public static Length<T> operator +(Length<T> first, Length<T> second)
{
return new Length<T>(first.Value + second.Value);
}
public static Length<T> operator -(Length<T> first, Length<T> second)
{
// I don't know any application where negative length makes sense,
// if it does feel free to remove Abs() and the exception in the constructor
return new Length<T>(System.Math.Abs(first.Value - second.Value));
}
// You can add more like
// public static Area<T> operator *(Length<T> x, Length<T> y)
// or
//public static Volume<T> operator *(Length<T> x, Length<T> y, Length<T> z)
// etc
public Length<R> To<R>() where R : struct, ILength
{
//notice how I got rid of the Activator invocations by moving them in a static field;
//double mult = new T().ToSiFactor;
//double div = new R().ToSiFactor;
return new Length<R>(Value * SiFactor / Length<R>.SiFactor);
}
}
Notice also that, in order to save us from the dreaded Activator call, I stored the result of new T().ToSiFactor in SiFactor. It might seem awkward at first, but as Length is generic, Length<mm> will have its own copy, Length<Km> its own, and so on and so forth. Please note that ToSiFactor is the toBase of your approach.
The problem that I see is that as long as you are in the realm of simple units and up to the first derivative of time, things are simple. If you try to do something more complex, then you can see the drawbacks of this approach. Typing
var accel = new Acceleration<m, s, s>(1.2);
will not be as clear and "smooth" as
let accel = 1.2<m/sec^2>
And regardless of the approach, you will have to specify every math operation you will need with hefty operator overloading, while in F# you have this for free, even if the results are not meaningful as I was writing at the beginning.
The last drawback (or advantage depending on how you see it) of this design, is that it can't be unit agnostic. If there are cases that you need "just a Length" you can't have it. You need to know each time if your Length is millimeters, statute mile or foot. I took the opposite approach in SharpConvert and LengthUnit derives from UnitBase and Meters Kilometers etc derive from this. That's why I couldn't go down the struct path by the way. That way you can have:
LengthUnit l1 = new Meters(12);
LengthUnit l2 = new Feet(15.4);
LengthUnit sum = l1 + l2;
sum will be meters but one shouldn't care as long as they want to use it in the next operation. If they want to display it, then they can call sum.To<Kilometers>() or whatever unit. To be honest, I don't know if not "locking" the variable to a specific unit has any advantages. It might worth investigating it at some point.
I would like the compiler to help me as much as possible. So maybe you could have a TypedInt where T contains the actual unit.
public struct TypedInt<T>
{
public int Value { get; }
public TypedInt(int value) => Value = value;
public static TypedInt<T> operator -(TypedInt<T> a, TypedInt<T> b) => new TypedInt<T>(a.Value - b.Value);
public static TypedInt<T> operator +(TypedInt<T> a, TypedInt<T> b) => new TypedInt<T>(a.Value + b.Value);
public static TypedInt<T> operator *(int a, TypedInt<T> b) => new TypedInt<T>(a * b.Value);
public static TypedInt<T> operator *(TypedInt<T> a, int b) => new TypedInt<T>(a.Value * b);
public static TypedInt<T> operator /(TypedInt<T> a, int b) => new TypedInt<T>(a.Value / b);
// todo: m² or m/s
// todo: more than just ints
// todo: other operations
public override string ToString() => $"{Value} {typeof(T).Name}";
}
You could have an extensiom method to set the type (or just new):
public static class TypedInt
{
public static TypedInt<T> Of<T>(this int value) => new TypedInt<T>(value);
}
The actual units can be anything. That way, the system is extensible.
(There's multiple ways of handling conversions. What do you think is best?)
public class Mile
{
// todo: conversion from mile to/from meter
// maybe define an interface like ITypedConvertible<Meter>
// conversion probably needs reflection, but there may be
// a faster way
};
public class Second
{
}
This way, you can use:
var distance1 = 10.Of<Mile>();
var distance2 = 15.Of<Mile>();
var timespan1 = 4.Of<Second>();
Console.WriteLine(distance1 + distance2);
//Console.WriteLine(distance1 + 5); // this will be blocked by the compiler
//Console.WriteLine(distance1 + timespan1); // this will be blocked by the compiler
Console.WriteLine(3 * distance1);
Console.WriteLine(distance1 / 3);
//Console.WriteLine(distance1 / timespan1); // todo!
See Boo Ometa (which will be available for Boo 1.0):
Boo Ometa and Extensible Parsing
I really liked reading through this stack overflow question and its answers.
I have a pet project that I've tinkered with over the years, and have recently started re-writing it and have released it to the open source at https://github.com/MafuJosh/NGenericDimensions
It happens to be somewhat similar to many of the ideas expressed in the question and answers of this page.
It basically is about creating generic dimensions, with the unit of measure and the native datatype as the generic type placeholders.
For example:
Dim myLength1 as New Length(of Miles, Int16)(123)
With also some optional use of Extension Methods like:
Dim myLength2 = 123.miles
And
Dim myLength3 = myLength1 + myLength2
Dim myArea1 = myLength1 * myLength2
This would not compile:
Dim myValue = 123.miles + 234.kilograms
New units can be extended in your own libraries.
These datatypes are structures that contain only 1 internal member variable, making them lightweight.
Basically, the operator overloads are restricted to the "dimension" structures, so that every unit of measure doesn't need operator overloads.
Of course, a big downside is the longer declaration of the generics syntax that requires 3 datatypes. So if that is a problem for you, then this isn't your library.
The main purpose was to be able to decorate an interface with units in a compile-time checking fashion.
There is a lot that needs to be done to the library, but I wanted to post it in case it was the kind of thing someone was looking for.

Categories