How to implement IComparable<Time> in my Struct? - c#

My code includes struct called Time.
I would like to implement IComparable<Time> interface in my struct to compare two variables of type 'Time'.
I've already did it with IEquatable and it works, but I can't figure out how to do it with IComparable.
Since Time consists of three variables (hours, min, sec) I can't simply consider each case in if. Or can I? Could you give me a hint how to code it? Thank you.
{
public struct Time : IEquatable<Time>, IComparable<Time>
{
private byte hours, minutes, seconds;
public byte Hours { get { return hours; } }
public byte Minutes { get { return minutes; } }
public byte Seconds { get { return seconds; } }
public Time(byte hh, byte mm, byte ss)
{
if (hh < 0 || hh > 24)
throw new ArgumentOutOfRangeException();
if (mm < 0 || mm > 60)
throw new ArgumentOutOfRangeException();
if (ss < 0 || ss > 60)
throw new ArgumentOutOfRangeException();
this.hours = hh;
this.minutes = mm;
this.seconds = ss;
}
public Time(byte hh, byte mm) : this(hh, mm, default(byte)) { }
public Time(byte hh) : this(hh, default(byte), default(byte)) { }
public Time(string hms)
{
string[] arr = hms.Split(':');
this.hours = Convert.ToByte(arr[0]);
this.minutes = Convert.ToByte(arr[1]);
this.seconds = Convert.ToByte(arr[2]);
}
public override string ToString()
{
return Hours + ":" + Minutes + ":" + Seconds;
}
public override bool Equals(object t)
{
if (t == null || this.GetType() != t.GetType()) return false;
return (this.Hours == ((Time)t).Hours &&
this.Minutes == ((Time)t).Minutes &&
this.Seconds == ((Time)t).Seconds);
}
public override int GetHashCode()
{
return this.GetHashCode();
}
// IEquatable
public bool Equals(Time other)
{
return this.Equals((object)other);
}
public static bool operator == (Time t1, Time t2)
{
return t1.Equals(t2);
}
public static bool operator !=(Time t1, Time t2)
{
return !t1.Equals(t2);
}
// IComparable
public int CompareTo(Time other)
{
if (this == other)
return 0;
// Code that compares two variables
}
public static bool operator > (Time t1, Time t2)
{
return t1.CompareTo(t2) == 1;
}
public static bool operator < (Time t1, Time t2)
{
return t1.CompareTo(t2) == -1;
}
public static bool operator >= (Time t1, Time t2)
{
return t1.CompareTo(t2) >= 0;
}
public static bool operator <= (Time t1, Time t2)
{
return t1.CompareTo(t2) <= 0;
}
}
}

public int CompareTo(Time other)
{
var by_hour = this.Hours - other.Hours;
if (by_hour != 0)
return by_hour;
var by_minute = this.Minutes - other.Minutes;
if (by_minute != 0)
return by_minute;
return this.Seconds - other.Seconds;
}
Also change all places where you use the Compare method to account for the fact that it can return non-zero values other than 1 and -1.

Related

Implementing numeric limit class

I am new to C# and trying to implement a numeric limit class as :
internal class NumericLimit<TValue> where TValue : IComparable
{
public NumericLimit(TValue min, TValue max)
{
this.Max = max;
this.Min = min;
}
internal TValue Max { get; }
internal TValue Min { get; }
internal bool WithinBounds(TValue min, TValue max)
{
if (min.CompareTo(this.Min) <= 0 &&
max.CompareTo(this.Max) >= 0)
return true;
return false;
}
internal bool LessThan(TValue value)
{
return (value.CompareTo(this.Max) > 0);
}
internal bool GreaterThan(TValue value)
{
return (value.CompareTo(this.Min) < 0);
}
internal bool Contains(TValue value)
{
if (value.CompareTo(this.Max) == 0 ||
value.CompareTo(this.Min) == 0)
return true;
return (value.CompareTo(this.Min) > 0) &&
(value.CompareTo(this.Max) < 0);
}
internal bool Defined()
{
return true;
}
}
The problem is how to implement Defined() function. I want the NumericLimit to be invalid/undefined when both Min and Max values are -1.
Like, for NumericLimit<long> the limit is undefined when both Min and Max are -1L.
And for NumericLimit<int> the limit is undefined when both Min and Max are -1.
How to implement 'Defined' in a way that correctly represents negative one for TValue type ?
What if after some time you decide to use NumericLimit<double> or some other type for T that will not accept value of -1? I suggest using special IsDefined flag and adding static method for constructing undefined limit:
internal class NumericLimit<TValue> where TValue : IComparable
{
internal bool IsDefined { get; }
public NumericLimit(TValue min, TValue max)
{
this.Max = max;
this.Min = min;
IsDefined = true;
}
private NumericLimit()
{
IsDefined = false;
}
public static NumericLimit<TValue> Undefined()
{
return new NumericLimit<TValue>();
}
// ...
}

How to have multiple argument's in a C# if statement

[That title may be wrong for the question, please inform me if so]
I'm coding a little maths quiz in C#, and I was wondering how to make an if statement that says something similiar to:
"if the user responds with 'this' or ' this'
{
do blahblahblah
}
But I don't know how to say the OR bit in C#, I looked through the C# operators page, but kind of got lost in the technical jargon (I'm a rookie).
This is what I have so far:
Console.WriteLine("What is 200 / 5?");
string sFirstAnswer = Console.ReadLine();
if (sFirstAnswer == "40" || " 40")
{
sUser1Score++;
Console.WriteLine("\n Correct, 200 / 5 = 40. You have been awarded 1 point.");
Console.ReadLine();
}
Write
if (sFirstAnswer == "40" || sFirstAnswer == " 40")
or better yet, trim the answer:
if (sFirstAnswer.Trim() == "40")
if (sFirstAnswer == "40" || sFirstAnswer == "40")
You can create a list of allowed answers and then check it's in the list.
var correctFirstAnswers = new List<string>{"40", " 40"};
if (correctFirstAnswers.Contains(sFirstAnswer))
this is more readable than || when there are multiple possible answers.
I thought I might give an (over-the-top) example of what I meant to make it a bit more Dynamic
A few classes now help to ask you the questions, and with a few functions built around it, you can easily show your questions in a menu format, and then ask the question, with random nr's (only whole number division was a bit more annoying :))
You could make it easier that the Generate method limits the range a bit more, but I just thought I wanted to give you an idea of how it could look like
using System;
using System.Collections.Generic;
namespace MathQuiz
{
class Program
{
interface IExercise
{
string Title { get; }
void Generate();
}
abstract class Exercise<TResult> : IExercise
{
public virtual string Title
{
get
{
return "Exercise";
}
}
public abstract bool isCorrect(TResult reply);
public abstract TResult Solve();
public abstract bool TryParse(string value, out TResult result);
public abstract void Generate();
}
abstract class ExerciseWith2Items<TSource, TResult> : Exercise<TResult>
{
public virtual TSource Item1 { get; set; }
public virtual TSource Item2 { get; set; }
public abstract string Operator { get; }
public override string ToString()
{
return string.Format("{0} {1} {2}", Item1, Operator, Item2);
}
}
abstract class WholeNumberExercise : ExerciseWith2Items<int, int>
{
public override void Generate()
{
Random next = new Random();
Item1 = next.Next(100) + 15;
Item2 = next.Next(100) + 15;
}
public override bool TryParse(string value, out int result)
{
return int.TryParse(value, out result);
}
}
class Division : WholeNumberExercise
{
protected bool IsPrime(int nr)
{
int max = (int)Math.Sqrt(nr);
if (nr <= 2)
{
return true;
}
for (int i = 2; i < max; i++)
{
if (nr % i == 0)
{
return false;
}
}
return true;
}
public override int Item1
{
get
{
return base.Item1;
}
set
{
// primes cannot be divived, so increase the value until we don't have a prime
while (IsPrime(value))
{
value++;
}
base.Item1 = value;
}
}
public override int Item2
{
get
{
return base.Item2;
}
set
{
if (value <= 0)
{
// minimum 2
value = 2;
}
// small override: we only want whole number division, so change the nr to the closest nr that has no rest after division
int closest = 0;
while ((value - closest > 1 && Item1 % (value - closest) != 0) ||
(value + closest < Item1 && Item1 % (value + closest) != 0))
{
closest++;
}
// in case closest == 0, it doesn't really change anything
if (Item1 % (value - closest) == 0)
{
value -= closest;
}
else
{
value += closest;
}
base.Item2 = value;
}
}
public override string Operator
{
get { return "/"; }
}
public override bool isCorrect(int reply)
{
return reply == (Item1 / Item2);
}
public override void Generate()
{
Random r = new Random();
Item1 = r.Next(500) + 100;
Item2 = r.Next(50) + 2;
}
public override int Solve()
{
return (Item1 / Item2);
}
}
class Multiplication : WholeNumberExercise
{
public override string Operator
{
get { return "*"; }
}
public override bool isCorrect(int reply)
{
return reply == (Item1 * Item2);
}
public override int Solve()
{
return (Item1 * Item2);
}
}
class Addition : WholeNumberExercise
{
public override string Operator
{
get { return "+"; }
}
public override bool isCorrect(int reply)
{
return reply == (Item1 + Item2);
}
public override int Solve()
{
return (Item1 + Item2);
}
}
class Subtraction : WholeNumberExercise
{
public override string Operator
{
get { return "-"; }
}
public override bool isCorrect(int reply)
{
return reply == (Item1 - Item2);
}
public override int Solve()
{
return (Item1 - Item2);
}
}
static IExercise ShowMenu(IList<IExercise> exercises)
{
int menu;
do
{
Console.Clear();
Console.WriteLine("Test your match skills :)\r\n");
for (int i = 0; i < exercises.Count; i++)
{
Console.WriteLine("\t{0}\t{1}", i, exercises[i].GetType().Name);
}
Console.WriteLine("\r\n\t99\tExit\r\n");
Console.Write("Please enter your choice: ");
if (!int.TryParse(Console.ReadLine(), out menu))
{
// wrong input
menu = -1;
}
if (menu != 99)
{
if (menu >= exercises.Count)
{
menu = -1;
}
}
} while (menu < 0);
IExercise result = null;
if (menu != 99)
{
result = exercises[menu];
}
return result;
}
static void Solve(IExercise exercise)
{
if (exercise == null)
{
return;
}
if (!(exercise is WholeNumberExercise))
{
Console.WriteLine("Don't know how to solve this exercise, please contact developer :)");
Console.ReadLine();
return;
}
var solvable = exercise as WholeNumberExercise;
solvable.Generate();
Console.Write("{0}: '{1}' = ", solvable.GetType().Name, exercise);
int reply;
bool validAnswerGiven;
do
{
validAnswerGiven = solvable.TryParse(Console.ReadLine(), out reply);
if (validAnswerGiven)
{
if (solvable.isCorrect(reply))
{
Console.WriteLine("Correct!");
}
else
{
Console.WriteLine("Incorrect, the correct result is {0}", solvable.Solve());
}
}
else
{
Console.WriteLine("Please enter valid value (whole number)!");
}
} while (!validAnswerGiven);
Console.ReadLine();
}
static void Main(string[] args)
{
IList<IExercise> potentialExercises = new List<IExercise>()
{
new Addition(),
new Subtraction(),
new Division(),
new Multiplication()
};
IExercise selectedExercise;
do
{
selectedExercise = ShowMenu(potentialExercises);
Solve(selectedExercise);
} while (selectedExercise != null);
Console.WriteLine("Program completed!");
}
}
}
it is runnable code, so copy and paste in visual studio console project should do the trick ;)
In addition to the above you could also try to convert the string to an integer
int number = 0
bool result = Int32.TryParse(Console.ReadLine(), out number);
if (number== 40){
...
}
number will be 0 if conversion fails to int and result false but for your case you dont care its not 40...
MSDN Int TryParse
Since you're validating an answer from an equation, you want to Parse it and get it into a numeric form pronto.
var answer = Convert.ToInt32(sFirstAnswer.Trim());
var expected = 40;
if(answer == expected){
//gold ribbon
}

How do you create your own DataType?

I would like to create my own DataType called positiveInteger.
I know what you are thinking?
You are thinking that I should use uint here.
But uint contains 0 and I want only positive numbers.
Now you may tell me that Create a class called positiveInteger.
Yes, I can create a Class called positiveIntegerbut I don't know how to implement that class such that this new DataType accepts only positive integer values?
If you want to be able to "accept" values, which are (mostly) compiled as constant int values, then you'll need to implement an implicit conversion to positiveInteger from int
public class positiveInteger
{
public static implicit operator positiveInteger(int source)
{
if(source <= 0) throw new ArgumentOutOfRangeException();
}
}
This will allow you to assign a positiveInteger like so
positiveInteger number = 5;
It will also, however, make it possible to assign an int value
int i = 5;
positiveInteger number = i; // This will throw an exception when i <= 0
An example imlementation could be:
public struct PositiveInteger : IEquatable<PositiveInteger>, IComparable<PositiveInteger>
{
public PositiveInteger(uint value)
{
if (value <= 0) throw new ArgumentOutOfRangeException();
_value = value;
}
public uint Value { get { return _value == 0 ? 1 : _value; } }
private readonly uint _value;
public static implicit operator PositiveInteger(uint value)
{
return new PositiveInteger(value);
}
public static implicit operator uint(PositiveInteger value)
{
return value.Value;
}
public static PositiveInteger operator +(PositiveInteger value1, PositiveInteger value2)
{
var result = value1.Value + value2.Value;
if (result < value1.Value || result < value2.Value)
{
throw new ArgumentOutOfRangeException(); //overflow
}
return result;
}
public static PositiveInteger operator -(PositiveInteger value1, PositiveInteger value2)
{
if (value1.Value < value2.Value) throw new ArgumentOutOfRangeException();
return value1.Value - value2.Value;
}
public override bool Equals(object obj)
{
if (obj is PositiveInteger == false) return false;
return Equals((PositiveInteger)obj);
}
public bool Equals(PositiveInteger other)
{
return Value == other.Value;
}
public override int GetHashCode()
{
return (int)Value;
}
public int CompareTo(PositiveInteger other)
{
if (Value == other.Value) return 0;
return Value < other.Value ? -1 : 1;
}
public override string ToString()
{
return Value.ToString(CultureInfo.InvariantCulture);
}
}
And a small test:
void Test()
{
var list = new List<PositiveInteger> {5, 1, 3};
list.Sort(); // 1,3,5
var a = new PositiveInteger(1);
var b = new PositiveInteger(2);
var c = a + b; // = 3
var d = c - b; // = 1
var e = d - a; // throws ArgumentOutOfRangeException
}
Try this for your constructor. But it is still not a good idea because you should still validate all data before you use it. Just like checking that a denominator is not zero before blindly dividing.
public class PositiveInteger {
private uint _value;
public PositiveInteger(int x) {
if (x < 1) {
throw new Exception("Invalid value. Value is not positive.");
}
_value = x;
}
}

How to represent integer infinity?

I need a way to represent an integer number that can be infinite. I'd prefer not to use a floating point type (double.PositiveInfinity) since the number can never be fractional and this might make the API confusing. What is the best way to do this?
Edit: One idea I haven't seen yet is using int? with null representing infinity. Are there any good reasons not to do this?
If you don't need the full range of integer values, you can use the int.MaxValue and int.MinValue constants to represent infinities.
However, if the full range of values is required, I'd suggest either creating a wrapper class or simply going for doubles.
An example partial implementation along the lines of the comments of SLaks and others (feedback welcome):
Usage:
int x = 4;
iint pi = iint.PositiveInfinity;
iint ni = iint.NegativeInfinity;
Assert.IsTrue(x + pi == iint.PositiveInfinity);
Assert.IsTrue(pi + 1 == iint.PositiveInfinity);
Assert.IsTrue(pi + (-ni) == iint.PositiveInfinity);
Assert.IsTrue((int)((iint)5) == 5);
Implementation:
public struct iint
{
private readonly int _int;
public iint(int value)
{
if(value == int.MaxValue || value == int.MinValue)
throw new InvalidOperationException("min/max value reserved in iint");
_int = value;
}
public static explicit operator int(iint #this)
{
if(#this._int == int.MaxValue || #this._int == int.MinValue)
throw new InvalidOperationException("cannot implicit convert infinite iint to int");
return #this._int;
}
public static implicit operator iint(int other)
{
if(other == int.MaxValue || other == int.MinValue)
throw new InvalidOperationException("cannot implicit convert max-value into to iint");
return new iint(other);
}
public bool IsPositiveInfinity {get { return _int == int.MaxValue; } }
public bool IsNegativeInfinity { get { return _int == int.MinValue; } }
private iint(bool positive)
{
if (positive)
_int = int.MaxValue;
else
_int = int.MinValue;
}
public static readonly iint PositiveInfinity = new iint(true);
public static readonly iint NegativeInfinity = new iint(false);
public static bool operator ==(iint a, iint b)
{
return a._int == b._int;
}
public static bool operator !=(iint a, iint b)
{
return a._int != b._int;
}
public static iint operator +(iint a, iint b)
{
if (a.IsPositiveInfinity && b.IsNegativeInfinity)
throw new InvalidOperationException();
if (b.IsPositiveInfinity && a.IsNegativeInfinity)
throw new InvalidOperationException();
if (a.IsPositiveInfinity)
return PositiveInfinity;
if (a.IsNegativeInfinity)
return NegativeInfinity;
if (b.IsPositiveInfinity)
return PositiveInfinity;
if (b.IsNegativeInfinity)
return NegativeInfinity;
return a._int + b._int;
}
public static iint operator -(iint a, iint b)
{
if (a.IsPositiveInfinity && b.IsPositiveInfinity)
throw new InvalidOperationException();
if (a.IsNegativeInfinity && b.IsNegativeInfinity)
throw new InvalidOperationException();
if (a.IsPositiveInfinity)
return PositiveInfinity;
if (a.IsNegativeInfinity)
return NegativeInfinity;
if (b.IsPositiveInfinity)
return NegativeInfinity;
if (b.IsNegativeInfinity)
return PositiveInfinity;
return a._int - b._int;
}
public static iint operator -(iint a)
{
if (a.IsNegativeInfinity)
return PositiveInfinity;
if (a.IsPositiveInfinity)
return NegativeInfinity;
return -a;
}
/* etc... */
/* other operators here */
}
Your API can use a convention that int.MaxValue represents positive infinity value and int.MinValue - negative infinity.
But you still need to document it somewhere and, may be you will need some operations with your infinite integer:
/// <summary>
/// Making int infinity
/// ...
/// </summary>
public static class IntExtension
{
public const int PositiveInfinity = int.MaxValue;
public const int NegativeInfinity = int.MinValue;
public static bool IsPositiveInfinity(this int x)
{
return x == PositiveInfinity;
}
public static bool IsNegativeInfinity(this int x)
{
return x == NegativeInfinity;
}
public static int Operation(this int x, int y)
{
// ...
return PositiveInfinity;
}
}
Another partial implementation (I see Jack was faster):
struct InfinityInt
{
readonly int Value;
InfinityInt(int value, bool allowInfinities)
{
if (!allowInfinities && (value == int.MinValue || value == int.MaxValue))
throw new ArgumentOutOfRangeException("value");
Value = value;
}
public InfinityInt(int value)
: this(value, false)
{
}
public static InfinityInt PositiveInfinity = new InfinityInt(int.MaxValue, true);
public static InfinityInt NegativeInfinity = new InfinityInt(int.MinValue, true);
public bool IsAnInfinity
{
get { return Value == int.MaxValue || Value == int.MinValue; }
}
public override string ToString()
{
if (Value == int.MinValue)
return double.NegativeInfinity.ToString();
if (Value == int.MaxValue)
return double.PositiveInfinity.ToString();
return Value.ToString();
}
public static explicit operator int(InfinityInt ii)
{
if (ii.IsAnInfinity)
throw new OverflowException();
return ii.Value;
}
public static explicit operator double(InfinityInt ii)
{
if (ii.Value == int.MinValue)
return double.NegativeInfinity;
if (ii.Value == int.MaxValue)
return double.PositiveInfinity;
return ii.Value;
}
public static explicit operator InfinityInt(int i)
{
return new InfinityInt(i); // can throw
}
public static explicit operator InfinityInt(double d)
{
if (double.IsNaN(d))
throw new ArgumentException("NaN not supported", "d");
if (d >= int.MaxValue)
return PositiveInfinity;
if (d <= int.MinValue)
return NegativeInfinity;
return new InfinityInt((int)d);
}
static InfinityInt FromLongSafely(long x)
{
if (x >= int.MaxValue)
return PositiveInfinity;
if (x <= int.MinValue)
return NegativeInfinity;
return new InfinityInt((int)x);
}
public static InfinityInt operator +(InfinityInt a, InfinityInt b)
{
if (a.IsAnInfinity || b.IsAnInfinity)
{
if (!b.IsAnInfinity)
return a;
if (!a.IsAnInfinity)
return b;
if (a.Value == b.Value)
return a;
throw new ArithmeticException("Undefined");
}
return FromLongSafely((long)a.Value + (long)b.Value);
}
public static InfinityInt operator *(InfinityInt a, InfinityInt b)
{
if (a.IsAnInfinity || b.IsAnInfinity)
{
if (a.Value == 0 || b.Value == 0)
throw new ArithmeticException("Undefined");
return (a.Value > 0) == (b.Value > 0) ? PositiveInfinity : NegativeInfinity;
}
return FromLongSafely((long)a.Value * (long)b.Value);
}
// and so on, and so on
}
C# has a type for this the BigInteger class is unlimited size
http://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx
If you want the class to have a representation of infinity -- then wrap BigInteger in a class that gives it an infinity flag.
You will have to redefine all standard operators and conversions to get this to work.
How exactly to have operations on infinity work depends on your domain.
(For example in some forms of math you would like 2 x infinity = infinity and in some you don't).
How the details are implemented really depend on your domain problem and are not clear from your question.

How to specify to validate this situation with generics?

I'm trying to validate this class: min >= max. I realized using generics I can't use the comparators.
This is my generic class.
public class Range<T>
{
public T MinValue { get; set; }
public T MaxValue { get; set; }
public Range() { }
public Range(T min, T max)
{
this.MinValue = min;
this.MaxValue = max;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var other = obj as Range<T>;
return this.MinValue.Equals(other.MinValue) &&
this.MaxValue.Equals(other.MaxValue);
}
public override string ToString()
{
return string.Format("{0},{1}", this.MinValue, this.MaxValue);
}
}
T datatype can be only numbers, is there a way to accept just numbers and accept the <=?
No, you can't constrain generics to numbers, but you can constrain T to IComparable<T> and then use CompareTo()
public class Range<T> where T : IComparable<T>
{
....
}
Then you can say:
if (min.CompareTo(max) >= 0)...
And throw a validation exception or whatever validation you'd like. You can use the same thing to make sure value is >= min and <= max.
if (value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0)...
public class Range<T> where T : IComparable<T>
{
...
public bool Check(T value)
{
return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
}
}
If you range between 0 and 10, and want 0, 10 to fail (exclude min and max) - simply replace ">=" with ">" and "<=" with "<".
I would also recommend changing in the Equals override from:
return this.MinValue.Equals(other.MinValue) &&
this.MaxValue.Equals(other.MaxValue);
to this:
return this.MinValue.CompareTo(other.MinValue) == 0 &&
this.MaxValue.CompareTo(other.MaxValue) == 0;

Categories

Resources