Operator overloading? - c#

I've made myself a rss reader that keeps me up to date and informs me on new shows, or atleast thats the thought behind.
I've made a struct "SeasonEpisode" that hold two ints (season+episode) and a override ToString function.
I store the latest watched locally and i then read whats the newest is from the rss. But how could I compare SeasonEpisodes? right now I take each of the ints and compare them
if( se1.Season >= se2.Season )
if( se1.Episode > se2.Episode || se1.Season > se2.Season )
// new episode!
What i really want is
if( se1 > se2 )
// new episode
Could i get any help please?

There are two ways:
Implement IComparable<T> and use CompareTo
Overload the greater and less than operators
I suggest, you use both ways:
public class SeasonEpisode : IComparable<SeasonEpisode>
{
public int CompareTo(SeasonEpisode other)
{
if(other == null)
return 1;
if(Season == other.Season)
{
if(Episode == other.Episode)
return 0;
else if(Episode < other.Episode)
return -1;
else
return 1;
}
else if(Season < other.Season)
return -1;
else
return 1;
}
public static bool operator <(SeasonEpisode e1, SeasonEpisode e2)
{
return e1.CompareTo(e2) < 0;
}
public static bool operator >(SeasonEpisode e1, SeasonEpisode e2)
{
return e1.CompareTo(e2) > 0;
}
}

As i tripped over a NullReferenceException, here's an improvement (well this may be subjective ;-)) to Daniel Hilgarth's answer.
The only change is that it handles nulls in case the first argument to the > or < operator is null:
public class SeasonEpisode : IComparable<SeasonEpisode>
{
private static int Compare(SeasonEpisode e1, SeasonEpisode e2)
{
if (e1 == null && e2 == null)
return 0;
else if (e1 == null)
return -1;
else if (e2 == null)
return 1;
if(e1.Season == e2.Season)
{
if(e1.Episode == e2.Episode)
return 0;
else if(e1.Episode < e2.Episode)
return -1;
else
return 1;
}
else if(e1.Season < e2.Season)
return -1;
else
return 1;
}
public int CompareTo(SeasonEpisode other)
{
return Compare(this, other);
}
public static bool operator <(SeasonEpisode e1, SeasonEpisode e2)
{
return Compare(e1, e2) < 0;
}
public static bool operator >(SeasonEpisode e1, SeasonEpisode e2)
{
return Compare(e1, e2) > 0;
}
}

You can implement the IComparer<T> interface
Defines a method that a type implements to compare two objects.
You can implement IComparable if you want a class to be comparable to another instance of that class. Which is probably what you want, in this case.
Implement IComparer if you need a class that compares two objects.

Related

How to sort List<T> in c#

I've got a List<Card>, and I want to sort these cards
So, I'm looking for a method to sort them with different criterias, like their ID, their Name ...
public class Card : IComparer
{
public string ID;
public string Name;
public int CompareId(object firstCard, object secondCard)
{
Card c1 = (Card)firstCard;
Card c2 = (Card)secondCard;
return c1.Id.CompareTo(c2.Id);
}
}
But then, visual studio sent me an error :
'Card' does not implement interface member 'IComparer<Card>.Compare(Card, Card)'
You, probably, want to have your class Comparable not a Comparator
public class Card : IComparable<Card>
{
public string ID;
public string Name;
public int CompareTo(Card other)
{
if (null == other)
return 1;
// string.Compare is safe when Id is null
return string.Compare(this.Id, other.Id);
}
}
then
List<Card> myList = ...
myList.Sort();
Edit: If you want to have several criteria to choose from, you have to implement several Comparers as separated classes, e.g.
public sealed class CardByIdComparer : IComparer<Card>
{
public int Compare(Card x, Card y)
{
if (object.ReferenceEquals(x, y))
return 0;
else if (null == x)
return -1;
else if (null == y)
return 1;
else
return string.Compare(x.Id, y.Id);
}
}
and when sorting provide the required:
List<Card> myList = ...
myList.Sort(new CardByIdComparer());
Edit 2: (inspired by spender's library). If you want to combine several comparers into one (i.e. use comparer1, on tie - comparer2 etc.)
public sealed class ComparerCombined<T> : IComparer<T> {
private IComparer<T>[] m_Comparers;
public ComparerCombined(params IComparer<T>[] comparers) {
if (null == comparers)
throw new ArgumentNullException(nameof(comparers));
m_Comparers = comparers
.Select(item => item == null ? Comparer<T>.Default : item)
.Where(item => item != null)
.Distinct()
.ToArray();
}
public int Compare(T x, T y) {
if (object.ReferenceEquals(x, y))
return 0;
else if (null == x)
return -1;
else if (null == y)
return 1;
foreach (var comparer in m_Comparers) {
int result = comparer.Compare(x, y);
if (result != 0)
return result;
}
return 0;
}
}
usage:
myList.Sort(new ComparerCombined(
new CardByIdComparer(), // Sort By Id
new CardByNameComparer() // On tie (equal Id's) sort by name
));
The easiest way You can use Linq:
List<Card> objSortedList = objListObject.OrderBy(o=>o.ID).ToList();
or
List<Card> objSortedList = objListObject.OrderByDescending(o=>o.ID).ToList();
Good examples for demonstrate the concept of
List<T>.Sort(IComparer <T>) method check the link please.
IComparer<T> in this example compare method used for strings IComparer<T>
but you can use this for ID(int) too.
using System;
using System.Collections.Generic;
class GFG : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null || y == null)
{
return 0;
}
// "CompareTo()" method
return x.CompareTo(y);
}
}
public class geek
{
public static void Main()
{
List<string> list1 = new List<string>();
// list elements
list1.Add("C++");
list1.Add("Java");
list1.Add("C");
list1.Add("Python");
list1.Add("HTML");
list1.Add("CSS");
list1.Add("Scala");
list1.Add("Ruby");
list1.Add("Perl");
int range = 4;
GFG gg = new GFG();
Console.WriteLine("\nSort a range with comparer:");
// sort the list within a
// range of index 1 to 4
// where range = 4
list1.Sort(1, range, gg);
Console.WriteLine("\nBinarySearch and Insert Dart");
// Binary Search and storing
// index value to "index"
int index = list1.BinarySearch(0, range,
"Dart", gg);
if (index < 0)
{
list1.Insert(~index, "Dart");
range++;
}
}
}
You need to implement IComparer
public int Compare(Card card1, Card card2)
{
if (card1.ID > card2.ID)
return 1; //move card1 up
if (card2.ID < card1.ID)
return -1; //move card2 up
return 0; //do nothing
}

Question regarding declaration of equality operators in C#

This seems incredibly basic, but I couldn't find any other answers on this particular note. In declaring a == operator in C#, you must also declare the != operator. Obviously every case may vary based on type, but if a type has explicit equality or does not, is it reasonable to declare != as simply !(a == b)? Is there a reason NOT to do this? For example:
public static bool operator ==(Point p1, Point p2)
{
return ((p1.X == p2.x) && (p1.Y == p2.Y));
}
public static bool operator !=(Point p1, Point p2)
{
return !(p1 == p2);
}
There is a good example from Microsoft Docs: How to: Define Value Equality for a Type covering important aspects of defining equality for types.
In the following example, for x!=y you see it's simply returning !(x==y):
using System;
class TwoDPoint : IEquatable<TwoDPoint>
{
// Readonly auto-implemented properties.
public int X { get; private set; }
public int Y { get; private set; }
// Set the properties in the constructor.
public TwoDPoint(int x, int y)
{
if ((x < 1) || (x > 2000) || (y < 1) || (y > 2000))
{
throw new System.ArgumentException("Point must be in range 1 - 2000");
}
this.X = x;
this.Y = y;
}
public override bool Equals(object obj)
{
return this.Equals(obj as TwoDPoint);
}
public bool Equals(TwoDPoint p)
{
// If parameter is null, return false.
if (Object.ReferenceEquals(p, null))
{
return false;
}
// Optimization for a common success case.
if (Object.ReferenceEquals(this, p))
{
return true;
}
// If run-time types are not exactly the same, return false.
if (this.GetType() != p.GetType())
{
return false;
}
// Return true if the fields match.
// Note that the base class is not invoked because it is
// System.Object, which defines Equals as reference equality.
return (X == p.X) && (Y == p.Y);
}
public override int GetHashCode()
{
return X * 0x00010000 + Y;
}
public static bool operator ==(TwoDPoint lhs, TwoDPoint rhs)
{
// Check for null on left side.
if (Object.ReferenceEquals(lhs, null))
{
if (Object.ReferenceEquals(rhs, null))
{
// null == null = true.
return true;
}
// Only the left side is null.
return false;
}
// Equals handles case of null on right side.
return lhs.Equals(rhs);
}
public static bool operator !=(TwoDPoint lhs, TwoDPoint rhs)
{
return !(lhs == rhs);
}
}

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.

Compare types of keys for SortedDictionary

I want to write a custom comparer for a SortedDictionary, where keys are sorted based on their type. Is this possible?
public class StateBase
{
// This is a base class I have to inherit from
}
SortedDictionary<StateBase, int> _stateDictionary =
new SortedDictionary<StateBase, int>(new StateComparer());
class StateComparer : IComparer<StateBase>
{
public int Compare(StateBase a, StateBase b)
{
// I'd like to sort these based on their type
// I don't particularly care what order they are in, I just want them
// to be sorted.
}
}
Sure, why not? Note that we must be talking about reference-types for this to apply, so something like:
public class TypeComparer<T> : IComparer<T>, IEqualityComparer<T> where T : class
{
public static readonly TypeComparer<T> Singleton= new TypeComparer<T>();
private TypeComparer(){}
bool IEqualityComparer<T>.Equals(T x, T y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
Type xType = x.GetType(), yType = y.GetType();
return xType == yType && EqualityComparer<T>.Default.Equals(x, y);
}
int IEqualityComparer<T>.GetHashCode(T x)
{
if (x == null) return 0;
return -17*x.GetType().GetHashCode() + x.GetHashCode();
}
int IComparer<T>.Compare(T x, T y)
{
if(x==null) return y == null ? 0 : -1;
if (y == null) return 1;
Type xType = x.GetType(), yType = y.GetType();
int delta = xType == yType ? 0 : string.Compare(
xType.FullName, yType.FullName);
if (delta == 0) delta = Comparer<T>.Default.Compare(x, y);
return delta;
}
}
You can. If your comparer implements IComparer<T>, it can be passed to a new SortedDictionary instance by the corresponding constructor overload.
The Compare method then somehow decides what item is greater or lower. It is the place where you can implement your compare-by-type logic.
Here is an example to compare Type instances based on their name:
public class TypeComparer : IComparer<Type>
{
public int Compare(Type x, Type y)
{
if(x != null && y != null)
return x.FullName.CompareTo(y.FullName);
else if(x != null)
return x.FullName.CompareTo(null);
else if(y != null)
return y.FullName.CompareTo(null);
else
return 0;
}
}

C# Extend array type to overload operators

I'd like to create my own class extending array of ints. Is that possible? What I need is array of ints that can be added by "+" operator to another array (each element added to each), and compared by "==", so it could (hopefully) be used as a key in dictionary.
The thing is I don't want to implement whole IList interface to my new class, but only add those two operators to existing array class.
I'm trying to do something like this:
class MyArray : Array<int>
But it's not working that way obviously ;).
Sorry if I'm unclear but I'm searching solution for hours now...
UPDATE:
I tried something like this:
class Zmienne : IEquatable<Zmienne>
{
public int[] x;
public Zmienne(int ilosc)
{
x = new int[ilosc];
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return base.Equals((Zmienne)obj);
}
public bool Equals(Zmienne drugie)
{
if (x.Length != drugie.x.Length)
return false;
else
{
for (int i = 0; i < x.Length; i++)
{
if (x[i] != drugie.x[i])
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hash = x[0].GetHashCode();
for (int i = 1; i < x.Length; i++)
hash = hash ^ x[i].GetHashCode();
return hash;
}
}
Then use it like this:
Zmienne tab1 = new Zmienne(2);
Zmienne tab2 = new Zmienne(2);
tab1.x[0] = 1;
tab1.x[1] = 1;
tab2.x[0] = 1;
tab2.x[1] = 1;
if (tab1 == tab2)
Console.WriteLine("Works!");
And no effect. I'm not good with interfaces and overriding methods unfortunately :(. As for reason I'm trying to do it. I have some equations like:
x1 + x2 = 0.45
x1 + x4 = 0.2
x2 + x4 = 0.11
There are a lot more of them, and I need to for example add first equation to second and search all others to find out if there is any that matches the combination of x'es resulting in that adding.
Maybe I'm going in totally wrong direction?
For a single type, it is pretty easy to encapsulate, as below. Note that as a key you want to make it immutable too. If you want to use generics, it gets harder (ask for more info):
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
static class Program {
static void Main() {
MyVector x = new MyVector(1, 2, 3), y = new MyVector(1, 2, 3),
z = new MyVector(4,5,6);
Console.WriteLine(x == y); // true
Console.WriteLine(x == z); // false
Console.WriteLine(object.Equals(x, y)); // true
Console.WriteLine(object.Equals(x, z)); // false
var comparer = EqualityComparer<MyVector>.Default;
Console.WriteLine(comparer.GetHashCode(x)); // should match y
Console.WriteLine(comparer.GetHashCode(y)); // should match x
Console.WriteLine(comparer.GetHashCode(z)); // *probably* different
Console.WriteLine(comparer.Equals(x,y)); // true
Console.WriteLine(comparer.Equals(x,z)); // false
MyVector sum = x + z;
Console.WriteLine(sum);
}
}
public sealed class MyVector : IEquatable<MyVector>, IEnumerable<int> {
private readonly int[] data;
public int this[int index] {
get { return data[index]; }
}
public MyVector(params int[] data) {
if (data == null) throw new ArgumentNullException("data");
this.data = (int[])data.Clone();
}
private int? hash;
public override int GetHashCode() {
if (hash == null) {
int result = 13;
for (int i = 0; i < data.Length; i++) {
result = (result * 7) + data[i];
}
hash = result;
}
return hash.GetValueOrDefault();
}
public int Length { get { return data.Length; } }
public IEnumerator<int> GetEnumerator() {
for (int i = 0; i < data.Length; i++) {
yield return data[i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public override bool Equals(object obj)
{
return this == (obj as MyVector);
}
public bool Equals(MyVector obj) {
return this == obj;
}
public override string ToString() {
StringBuilder sb = new StringBuilder("[");
if (data.Length > 0) sb.Append(data[0]);
for (int i = 1; i < data.Length; i++) {
sb.Append(',').Append(data[i]);
}
sb.Append(']');
return sb.ToString();
}
public static bool operator ==(MyVector x, MyVector y) {
if(ReferenceEquals(x,y)) return true;
if(ReferenceEquals(x,null) || ReferenceEquals(y,null)) return false;
if (x.hash.HasValue && y.hash.HasValue && // exploit known different hash
x.hash.GetValueOrDefault() != y.hash.GetValueOrDefault()) return false;
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) return false;
for(int i = 0 ; i < xdata.Length ; i++) {
if(xdata[i] != ydata[i]) return false;
}
return true;
}
public static bool operator != (MyVector x, MyVector y) {
return !(x==y);
}
public static MyVector operator +(MyVector x, MyVector y) {
if(x==null || y == null) throw new ArgumentNullException();
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) throw new InvalidOperationException("Length mismatch");
int[] result = new int[xdata.Length];
for(int i = 0 ; i < xdata.Length ; i++) {
result[i] = xdata[i] + ydata[i];
}
return new MyVector(result);
}
}
Its not permitted to extend the array class, see the reference: http://msdn.microsoft.com/en-us/library/system.array.aspx
You could either implement IList (which has the basic methods), or encapsulate an Array in your class and provide conversion operators.
Please let me know if you need more detail.
Can you not just use the List class? This already does what you want via the AddRange method.
implement the ienumerable interface

Categories

Resources