c# similarity help - c#

Anyone can explain these codes for me?
public class SimilarityImages : IComparer<SimilarityImages>, IComparable
{
private readonly ComparableImage source;
private readonly ComparableImage destination;
private readonly double similarity;
public SimilarityImages(ComparableImage source, ComparableImage destination, double similarity)
{
this.source = source;
this.destination = destination;
this.similarity = similarity;
}
public ComparableImage Source
{
get
{
return source;
}
}
public ComparableImage Destination
{
get
{
return destination;
}
}
public double Similarity
{
get
{
return Math.Round(similarity * 100, 1);
}
}
public static int operator !=(SimilarityImages value, SimilarityImages compare)
{
return value.CompareTo(compare);
}
public static int operator <(SimilarityImages value, SimilarityImages compare)
{
return value.CompareTo(compare);
}
public static int operator ==(SimilarityImages value, SimilarityImages compare)
{
return value.CompareTo(compare);
}
public static int operator >(SimilarityImages value, SimilarityImages compare)
{
return value.CompareTo(compare);
}
public override string ToString()
{
return string.Format("{0}, {1} --> {2}", source.File.Name, destination.File.Name, similarity);
}
#region IComparer<SimilarityImages> Members
public int Compare(SimilarityImages x, SimilarityImages y)
{
return x.similarity.CompareTo(y.similarity);
}
#endregion
#region IComparable Members
public int CompareTo(object obj)
{
SimilarityImages other = (SimilarityImages)obj;
return this.Compare(this, other);
}
#endregion
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var other = (SimilarityImages)obj;
var equals = Source.File.FullName.Equals(other.Source.File.FullName, StringComparison.InvariantCultureIgnoreCase);
if (!equals)
{
return false;
}
equals = Destination.File.FullName.Equals(other.Destination.File.FullName, StringComparison.InvariantCultureIgnoreCase);
if (!equals)
{
return false;
}
return true;
}
public override int GetHashCode()
{
return string.Format("{0};{1}", Source.File.FullName, Destination.File.FullName).GetHashCode();
}
}

It looks kind of like String.Compare()
(Comparison of strings by value.)
however the return of integers for the operators <, >, <=, >=, ==, != is a bad practice - user expect a boolean return value.
Also, if the "images" are what I think they are (images as in a matrix of pixels), then returning a value for comparison is not intuitive - What comparison algorithm are you using? - Why are you providing only one comparison algorithm and hiding its name? - What if the images are not of same size or pixel format?

Related

C# Dictionary that uses an Unordered Pair as its Key?

I'm trying to create a Dictionary is C# that takes an Unordered Pair of Indices as its Key.
For example:
exampleDictionary[new UnorderedPair(x,y)] and exampleDictionary[new UnorderedPair(y,x)] should both return the same value.
Is there a way to create a custom unordered collection other than using a HashSet? Or some way to create an unordered Tuple?
This question is similar to what I'm trying to accomplish, except in C# rather than python.
If the type is not your own or you can't or don't want to modify refer to Theodor Zoulias's answer
Otherwise, assuming that UnorderedPair is your own class you can modify what you could do is e.g.
[Serializable]
public class UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
public T X;
public T Y;
public UnorderedPair()
{
}
public UnorderedPair(T x, T y)
{
X = x;
Y = y;
}
public bool Equals(UnorderedPair<T> other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
// For equality simply include the swapped check
return X.Equals(other.X) && Y.Equals(other.Y) || X.Equals(other.Y) && Y.Equals(other.X);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((UnorderedPair<T>)obj);
}
public override int GetHashCode()
{
// and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^
var hashX = X == null ? 0 : X.GetHashCode();
var hashY = Y == null ? 0 : Y.GetHashCode();
return HashCode.Combine(Math.Min(hashX,hashY), Math.Max(hashX,hashY));
}
public static bool operator ==(UnorderedPair<T> left, UnorderedPair<T> right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<T> left, UnorderedPair<T> right)
{
return !Equals(left, right);
}
}
and then e.g.
var testDict = new Dictionary<UnorderedPair<int>, string>();
testDict.Add(new UnorderedPair<int>(1,2), "Hello World!");
Console.WriteLine(testDict[new UnorderedPair<int>(2,1)]);
As per suggestion by Jodrell in the comments you could even make the types swappable - not sure this would be ever needed - but this way you could even have a pair of different types:
[Serializable]
public class UnorderedPair<TX, TY> : IEquatable<UnorderedPair<TX, TY>>
{
public TX X;
public TY Y;
public UnorderedPair()
{
}
public UnorderedPair(TX x, TY y)
{
X = x;
Y = y;
}
public UnorderedPair(TY y, TX x)
{
X = x;
Y = y;
}
public override int GetHashCode()
{
// and for the HashCode (used as key in HashSet and Dictionary) simply order them by size an hash them again ^^
var hashX = X == null ? 0 : X.GetHashCode();
var hashY = Y == null ? 0 : Y.GetHashCode();
var combine = HashCode.Combine(Math.Min(hashX, hashY), Math.Max(hashX, hashY));
return combine;
}
public bool Equals(UnorderedPair<TX, TY> other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (typeof(TX) != typeof(TY))
{
return EqualityComparer<TX>.Default.Equals(X, other.X) && EqualityComparer<TY>.Default.Equals(Y, other.Y);
}
return EqualityComparer<TX>.Default.Equals(X, other.X) && EqualityComparer<TY>.Default.Equals(Y, other.Y)
|| X.Equals(other.Y) && Y.Equals(other.X);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return obj switch
{
UnorderedPair<TX, TY> other => Equals(other),
UnorderedPair<TY, TX> otherSwapped => Equals(otherSwapped),
_ => false
};
}
public static bool operator ==(UnorderedPair<TX, TY> left, UnorderedPair<TX, TY> right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<TX, TY> left, UnorderedPair<TX, TY> right)
{
return !Equals(left, right);
}
public static implicit operator UnorderedPair<TX, TY>(UnorderedPair<TY, TX> pair)
{
return new UnorderedPair<TX, TY>(pair.Y, pair.X);
}
}
and
var testDict = new Dictionary<UnorderedPair<int, double>, string>();
testDict.Add(new UnorderedPair<int, double>(1,2.5), "Hello World!");
Console.WriteLine(testDict[new UnorderedPair<double,int>(2.5,1)]);
(.NET Fiddle for both)
You could write a custom IEqualityComparer<UnorderedPair<T>> implementation, and pass it as argument to the constructor of your Dictionary<UnorderedPair<TKey>, TValue>. This way you won't have to modify your UnorderedPair<T> type, by overriding its Equals and GetHashCode methods. Below is an example of such a comparer for the ValueTuple<T1, T2> struct, with both T1 and T2 being the same type:
class UnorderedValueTupleEqualityComparer<T> : IEqualityComparer<(T, T)>
{
private readonly IEqualityComparer<T> _comparer;
public UnorderedValueTupleEqualityComparer(IEqualityComparer<T> comparer = default)
{
_comparer = comparer ?? EqualityComparer<T>.Default;
}
public bool Equals((T, T) x, (T, T) y)
{
if (_comparer.Equals(x.Item1, y.Item1)
&& _comparer.Equals(x.Item2, y.Item2)) return true;
if (_comparer.Equals(x.Item1, y.Item2)
&& _comparer.Equals(x.Item2, y.Item1)) return true;
return false;
}
public int GetHashCode((T, T) obj)
{
int h1 = _comparer.GetHashCode(obj.Item1);
int h2 = _comparer.GetHashCode(obj.Item2);
if (h1 > h2) (h1, h2) = (h2, h1);
return HashCode.Combine(h1, h2);
}
}
Usage example:
Dictionary<(int, int), string> dictionary = new(
new UnorderedValueTupleEqualityComparer<int>());
Inspired by #derHugo's answer and my comments on it,
Fiddle here
A generic implementation,
#nullable enable
public class UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
private static IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
public T X { get; }
public T Y { get; }
public UnorderedPair(T x, T y)
{
X = x;
Y = y;
}
public bool Equals(UnorderedPair<T>? other)
{
if(other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
// For equality simply include the swapped check
return
comparer.Equals(X, other.X) && comparer.Equals(Y, other.Y)
||
comparer.Equals(X, other.Y) && comparer.Equals(Y, other.X);
}
public override bool Equals(object? obj)
{
return Equals(obj as UnorderedPair<T>);
}
public override int GetHashCode()
{
unchecked
{
return
(X is null ? 0 : comparer.GetHashCode(X))
+
(Y is null ? 0 : comparer.GetHashCode(Y));
}
}
public static bool operator ==(UnorderedPair<T>? left, UnorderedPair<T>? right)
{
return Equals(left, right);
}
public static bool operator !=(UnorderedPair<T>? left, UnorderedPair<T>? right)
{
return !Equals(left, right);
}
}
#nullable disable

GetHashCode() override coliding way to often

I'm using unity, and unity does not have a tuple in it, so I created my own tuple class to work since I needed it for my Dictionary.
Dictionary <Tuple<int,int>, Tile>
Tile class that I created and isn't really relevant to solve this problem(at least I think it wont help).
But the problem is that I'm using both negative and positive integer in my tuples, and when I use my current GetHashCode() with the Tuples, sometimes I get the same HashCode, for example Tuple<-10, 8> and Tuple<-9,-10> both gives -172 when I return the hashcode.
Is there any good GetHashCode that wouldn't get me conflicts?
To be honest I'm only using the operator ==, because I need to check if both tuples have the same integers inside of them, if I could get a operator == that only collides when both integer are the same and in the same order, it would solve my problem.
Some other minor problems, I can't get to understand the Equals override, as it is, it is working, but I don't know how well it works, since I kind of changed every single thing until it worked.
public class Tuple<T1, T2>
{
public T1 First { get; private set; }
public T2 Second { get; private set; }
public Tuple(T1 _First, T2 _Second)
{
First = _First;
Second = _Second;
}
public override int GetHashCode()
{
int hash = 0;
hash = First.GetHashCode() * 17 + Second.GetHashCode() + First.GetHashCode();
return hash;
}
public static bool operator==(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
{
if (ReferenceEquals(null, obj2))
return false;
return (obj1.GetHashCode() == obj2.GetHashCode());
}
public static bool operator!=(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
{
if (ReferenceEquals(null, obj2))
return true;
return !(obj1.GetHashCode() == obj2.GetHashCode());
}
public bool Equals(Tuple<T1, T2> other)
{
if (other == null)
return false;
if (GetHashCode() == other.GetHashCode())
return true;
else
return false;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
Tuple<T1, T2> other = obj as Tuple<T1, T2>;
return obj.GetType() == GetType() && Equals(other);
}
}
public static class Tuple
{
public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
{
var tuple = new Tuple<T1, T2>(first, second);
return tuple;
}
}
GetHashCode() isn't supposed to be collision free. You should use it to determine if two things might be the same objects, and then you have to actually do a thorough check to see if they are.
For example, your == method should be written more like this:
public static bool operator==(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
{
if (ReferenceEquals(null, obj2))
return false;
if (obj1.GetHashCode() != obj2.GetHashCode())
{
return false;
}
return DefaultComparer<T1>.Equals(obj1.First, obj2.First) && DefaultComparer<T2>.Equals(obj1.Second, obj2.Second);
}
Also, don't forget to consider the case where obj1 and obj2 are both null.
If you're implementing your own Tuple, you might consider just stealing Microsoft's from the Reference Source repository, or at least use it as a base for your own.
I'm using unity, and unity does not have a tuple in it
It supports Tuple if you have Unity 2017 and above.
Go to Edit --> Project Settings --> Player --> Other Settings --> Configuration --> Scripting Runtime Version --> .NET 4.x Equivalent.
Reload or restart Visual Studio and you should be able to use Tuple. If you are not using Unity 2017 and above and also don't want to update then see John's answer.
This is what resharper generates for you automatically. Just note how they do the GetHashCode() and Equals.
private class Tuple<T1,T2> : IEquatable<Tuple<T1, T2>>
{
public T1 First {get;}
public T2 Second {get;}
public Tuple(T1 first, T2 second)
{
First = first;
Second = second;
}
public bool Equals(Tuple<T1, T2> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EqualityComparer<T1>.Default.Equals(First, other.First) && EqualityComparer<T2>.Default.Equals(Second, other.Second);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Tuple<T1, T2>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (EqualityComparer<T1>.Default.GetHashCode(First) * 397) ^ EqualityComparer<T2>.Default.GetHashCode(Second);
}
}
public static bool operator ==(Tuple<T1, T2> left, Tuple<T1, T2> right)
{
return Equals(left, right);
}
public static bool operator !=(Tuple<T1, T2> left, Tuple<T1, T2> right)
{
return !Equals(left, right);
}
}
I have found PropertyCompare (*) to be useful in auto-generating Equals implementations. It will automatically compare all public properties (so if you add a new public property you don't need to change anything except GetHashCode (and even that is technically optional).
It uses Cache to be reasonably performant - it takes a one-off hit (per type) to generate the appropriate expressions for the comparisons.
using System;
using System.Linq.Expressions;
namespace YourApp
{
public class Tuple<T1, T2>
{
public T1 First { get; private set; }
public T2 Second { get; private set; }
public Tuple(T1 _First, T2 _Second)
{
First = _First;
Second = _Second;
}
public override int GetHashCode()
{
var hash = 0;
// Implement this however you like
hash = First.GetHashCode() * 17 + Second.GetHashCode() + First.GetHashCode();
return hash;
}
public static bool operator ==(Tuple<T1, T2> x, Tuple<T1, T2> y)
{
return PropertyCompare.Equal(x, y);
}
public static bool operator !=(Tuple<T1, T2> x, Tuple<T1, T2> y)
{
return !PropertyCompare.Equal(x, y);
}
public bool Equals(Tuple<T1, T2> other)
{
return PropertyCompare.Equal(this, other);
}
public override bool Equals(object obj)
{
return PropertyCompare.Equal(this, obj);
}
}
public static class Tuple
{
public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
{
var tuple = new Tuple<T1, T2>(first, second);
return tuple;
}
}
public class Program
{
public static void Main()
{
var bob1 = Tuple.New("a", 1);
var bob2 = Tuple.New("a", 1);
Console.WriteLine(bob1 == bob2);
Console.ReadLine();
}
}
public static class PropertyCompare
{
public static bool Equal<T>(T x, object y) where T : class
{
return Cache<T>.Compare(x, y as T);
}
public static bool Equal<T>(T x, T y)
{
if (x == null)
{
return y == null;
}
if (y == null)
{
return false;
}
return Cache<T>.Compare(x, y);
}
private static class Cache<T>
{
internal static readonly Func<T, T, bool> Compare;
static Cache()
{
var props = typeof(T).GetProperties();
if (props.Length == 0)
{
Compare = delegate { return true; };
return;
}
var x = Expression.Parameter(typeof(T), "x");
var y = Expression.Parameter(typeof(T), "y");
Expression body = null;
for (var i = 0; i < props.Length; i++)
{
var propEqual = Expression.Equal(
Expression.Property(x, props[i]),
Expression.Property(y, props[i]));
if (body == null)
{
body = propEqual;
}
else
{
body = Expression.AndAlso(body, propEqual);
}
}
Compare = Expression.Lambda<Func<T, T, bool>>(body, x, y)
.Compile();
}
}
}
}
(*) I found it online somewhere, alas I can't remember where and Google is failing me here.

How to avoid reference comparison with self implemented value types

I'm trying to implement a value type that in general mimics the behavior of type short.
So far comparison and assignments between my value type and short are working out fine, but when boxing jumps in the problems starts.
Below you can find a unit tests illustrating the problem as well as the source for my value type.
The first assert method uses the overriden Equals method of my value type, the second assert actually result in a reference comparison (RuntimeHelpers.Equals(this, obj);) which of course fails.
The test:
[TestMethod]
public void EqualsTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = SHORT_TYPE;
object shortObject = SHORT_TYPE;
object valueObject = valueType;
Assert.IsTrue(valueObject.Equals(shortObject)); // success
Assert.IsTrue(shortObject.Equals(valueObject)); // failed, comparing 2 references
}
The value type:
[ComVisible(true)]
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[DebuggerDisplay("{_Value}")]
public struct MyValueType : IComparable, IFormattable, IConvertible, IComparable<short>, IEquatable<short>, IEquatable<MyValueType>
{
readonly short _Value;
public int CompareTo(Object value)
{
if (value == null)
return 1;
if (value is MyValueType)
return _Value - ((MyValueType)value)._Value;
if (value is short)
return _Value - ((short)value);
throw new ArgumentException("argument must be MyValueType");
}
public int CompareTo(short value) { return _Value - value; }
public int CompareTo(MyValueType myValue) { return _Value - myValue._Value; }
public override bool Equals(Object obj) { return _Value == obj as short? || _Value == obj as MyValueType?; }
public bool Equals(MyValueType obj) { return _Value == obj._Value; }
public bool Equals(short obj) { return _Value == obj; }
public override int GetHashCode() { return ((ushort)_Value | (_Value << 16)); }
[SecuritySafeCritical]
public override String ToString() { return _Value.ToString(); }
[SecuritySafeCritical]
public String ToString(IFormatProvider provider) { return _Value.ToString(provider); }
public String ToString(String format) { return ToString(format, NumberFormatInfo.CurrentInfo); }
public String ToString(String format, IFormatProvider provider) { return ToString(format, NumberFormatInfo.GetInstance(provider)); }
[SecuritySafeCritical]
String ToString(String format, NumberFormatInfo info) { return _Value.ToString(format, info); }
public static MyValueType Parse(String s) { return Parse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); }
public static MyValueType Parse(String s, NumberStyles style) { return short.Parse(s, style); }
public static MyValueType Parse(String s, IFormatProvider provider) { return Parse(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); }
public static MyValueType Parse(String s, NumberStyles style, IFormatProvider provider) { return short.Parse(s, style, provider); }
static MyValueType Parse(String s, NumberStyles style, NumberFormatInfo info) { return short.Parse(s, style, info); }
public TypeCode GetTypeCode() { return TypeCode.Int16; }
bool IConvertible.ToBoolean(IFormatProvider provider) { return Convert.ToBoolean(_Value); }
char IConvertible.ToChar(IFormatProvider provider) { return Convert.ToChar(_Value); }
sbyte IConvertible.ToSByte(IFormatProvider provider) { return Convert.ToSByte(_Value); }
byte IConvertible.ToByte(IFormatProvider provider) { return Convert.ToByte(_Value); }
short IConvertible.ToInt16(IFormatProvider provider) { return _Value; }
ushort IConvertible.ToUInt16(IFormatProvider provider) { return Convert.ToUInt16(_Value); }
int IConvertible.ToInt32(IFormatProvider provider) { return Convert.ToInt32(_Value); }
uint IConvertible.ToUInt32(IFormatProvider provider) { return Convert.ToUInt32(_Value); }
long IConvertible.ToInt64(IFormatProvider provider) { return Convert.ToInt64(_Value); }
ulong IConvertible.ToUInt64(IFormatProvider provider) { return Convert.ToUInt64(_Value); }
float IConvertible.ToSingle(IFormatProvider provider) { return Convert.ToSingle(_Value); }
double IConvertible.ToDouble(IFormatProvider provider) { return Convert.ToDouble(_Value); }
Decimal IConvertible.ToDecimal(IFormatProvider provider) { return Convert.ToDecimal(_Value); }
DateTime IConvertible.ToDateTime(IFormatProvider provider) { throw new InvalidCastException(); }
Object IConvertible.ToType(Type type, IFormatProvider provider) { throw new NotImplementedException(); }
bool IEquatable<short>.Equals(short other) { return _Value.Equals(other); }
public MyValueType(short value) { _Value = value; }
public static implicit operator MyValueType(short value) { return new MyValueType(value); }
public static implicit operator short(MyValueType myValueType) { return myValueType._Value; }
//public static explicit operator MyValueType(short value) { return new MyValueType(value); }
//public static explicit operator short(MyValueType myValueType) { return myValueType; }
//public static bool operator ==(MyValueType first, MyValueType second) { return first._Value == second._Value; }
//public static bool operator !=(MyValueType first, MyValueType second) { return first._Value != second._Value; }
}
Edit: added complete lists of unit tests, failing asserts are at bottom and marked
[TestClass]
public class MyValueTypeTest
{
[TestMethod]
public void AssignShortTest()
{
MyValueType valueType = 1;
short shortType = valueType;
Assert.IsTrue(shortType == 1);
}
[TestMethod]
public void AssignValueTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = SHORT_TYPE;
Assert.IsTrue(valueType == 1);
}
[TestMethod]
public void DictionaryShortTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Dictionary<short, string> dict = new Dictionary<short, string>();
dict.Add(SHORT_TYPE, "short");
Assert.IsTrue(dict.ContainsKey(valueType));
}
[TestMethod]
public void DictionaryValueTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Dictionary<MyValueType, string> dict = new Dictionary<MyValueType, string>();
dict.Add(valueType, "value");
Assert.IsTrue(dict.ContainsKey(SHORT_TYPE));
}
[TestMethod]
public void EqualsOperatorTest()
{
const short SHORT_TYPE_A = 1;
MyValueType valueTypeA = 1;
MyValueType valueTypeB = 1;
Assert.IsTrue(valueTypeA == valueTypeB);
Assert.IsTrue(SHORT_TYPE_A == valueTypeA);
Assert.IsTrue(valueTypeA == SHORT_TYPE_A);
}
[TestMethod]
public void ShortEqualsTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Assert.IsTrue(SHORT_TYPE.Equals(valueType));
}
public static bool Test(Object objA, Object objB)
{
if (objA == objB)
return true;
if (objA == null || objB == null)
return false;
return objA.Equals(objB);
}
[TestMethod]
public void ValueEqualsTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Assert.IsTrue(valueType.Equals(SHORT_TYPE));
}
[TestMethod]
public void AreEqualTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Assert.AreEqual(valueType, SHORT_TYPE, "test 1"); // success
Assert.AreEqual(SHORT_TYPE, valueType, "test 2"); // failed, comparing 2 references
}
[TestMethod]
public void ObjectEqualsTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = 1;
Assert.IsTrue(object.Equals(valueType, SHORT_TYPE), "test 1"); // success
Assert.IsTrue(object.Equals(SHORT_TYPE, valueType), "test 2"); // failed, comparing 2 references
}
[TestMethod]
public void EqualsTest()
{
const short SHORT_TYPE = 1;
MyValueType valueType = SHORT_TYPE;
object shortObject = SHORT_TYPE;
object valueObject = valueType;
Assert.IsTrue(valueObject.Equals(shortObject), "test 1"); // success
Assert.IsTrue(shortObject.Equals(valueObject), "test 2"); // failed, comparing 2 references
}
}
You can't do this. Basically, there's no way of symmetrically implementing Equals between two types unless they know about each other.
Note that this assertion:
Assert.IsTrue(SHORT_TYPE.Equals(valueType));
works due to the implicit conversion. It's effectively using:
short converted = valueType;
Assert.IsTrue(SHORT_TYPE.Equals(converted));
That's not the same as your failing assertion, which is passing the boxed MyValueType to Int16.Equals(object).
I doubt that it's performing a reference comparison - it will be calling Int16.Equals(object) which will return false.
Fundamentally, I would give up on this hope - your type is definitely oddly-designed, in terms of implementing IEquatable<short> but not IEquatable<MyValueType> etc. This will behave in a way which is unexpected for many developers. You should revisit the whole design.

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;
}
}

Problem with IDictionary<Complex Key, Complex Value>.Remove() implementation

Hi I don't understand why this code doesn't work - it don't remove key; I still get "2" on output.
Bencode.BencodeDict d = new myTorrent.Bencode.BencodeDict();
d.Dict.Add(new Bencode.BencodeString("info"), new Bencode.BencodeString("1"));
d.Dict.Add(new Bencode.BencodeString("info2"), new Bencode.BencodeString("2"));
d.Dict.Add(new Bencode.BencodeString("info3"), new Bencode.BencodeString("3"));
d.Remove(new Bencode.BencodeString("info2"));
Bencode.BencodeVariable s1;
s1 = d[new Bencode.BencodeString("info2")];
if (s1 != null)
Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(s1.Encode()));
My BencodeDict and BencodeString
namespace myTorrent.Bencode
{
class BencodeDict : BencodeVariable, IDictionary<BencodeString, BencodeVariable>
{
private Dictionary<BencodeString, BencodeVariable> dict;
public BencodeDict() {
this.dict = new Dictionary<BencodeString,BencodeVariable>();
}
protected override void InternalDecode(BinaryReader data) { /*...*/ }
public override long ByteLength() { /*...*/ }
public override byte[] Encode() { /*...*/ }
//#region Overridden Methods
public override bool Equals(object ob)
{
if (ob == null)
return false;
BencodeDict y = ob as BencodeDict;
if (this.dict.Count != y.dict.Count)
return false;
BencodeVariable val;
foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
{
if (!y.TryGetValue(keypair.Key, out val))
return false;
if (!keypair.Value.Equals(val))
return false;
}
return true;
}
public override int GetHashCode()
{
int result = 0;
foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
{
result ^= keypair.Key.GetHashCode();
result ^= keypair.Value.GetHashCode();
}
return result;
}
#region IDictionary and IList methods
public void Add(BencodeString key, BencodeVariable value)
{
this.dict.Add(key, value);
}
public void Add(KeyValuePair<BencodeString, BencodeVariable> item)
{
this.dict.Add(item.Key, item.Value);
}
public void Clear()
{
this.dict.Clear();
}
public bool Contains(KeyValuePair<BencodeString, BencodeVariable> item)
{
if (!this.dict.ContainsKey(item.Key))
return false;
return this.dict[item.Key].Equals(item.Value);
}
public bool ContainsKey(BencodeString key)
{
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict) {
if (pair.Key.Equals(key))
return true;
}
return false;
}
public void CopyTo(KeyValuePair<BencodeString, BencodeVariable>[] array, int arrayIndex) { /*...*/ }
public int Count
{
get { return this.dict.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(BencodeString key)
{
return this.dict.Remove(key);
}
public bool Remove(KeyValuePair<BencodeString, BencodeVariable> item)
{
return this.dict.Remove(item.Key);
}
public bool TryGetValue(BencodeString key, out BencodeVariable value)
{
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
if ( pair.Key.Equals(key) ) {
value = pair.Value;
return true;
}
value = null;
return false;
}
public BencodeVariable this[BencodeString key]
{
get {
foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
if ( pair.Key.Equals(key) )
return pair.Value;
return null;
}
set { this.dict[key] = value; }
}
public ICollection<BencodeString> Keys
{
get { return this.dict.Keys; }
}
public ICollection<BencodeVariable> Values
{
get { return this.dict.Values; }
}
public IEnumerator<KeyValuePair<BencodeString, BencodeVariable>> GetEnumerator()
{
return this.dict.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.dict.GetEnumerator();
}
#endregion
}
}
class BencodeString : BencodeVariable
{
private byte[] str;
public BencodeString() {
this.str = null;
}
public BencodeString(string str) {
this.str = encoding.GetBytes(str);
}
public override bool Equals(object ob)
{
if (ob == null)
return false;
BencodeString y = ob as BencodeString;
return (encoding.GetString(this.str) == encoding.GetString(y.str));
}
public override int GetHashCode()
{
return this.str.GetHashCode();
}
}
You're relying on byte[].GetHashCode() doing something desirable. It won't. Arrays don't implement equality or hash operations - you'll get the default (identity) behaviour.
Rewrite your GetHashCode method as something like this:
public override int GetHashCode()
{
int result = 17;
foreach (byte b in str)
{
result = result * 31 + b;
}
return result;
}
(Also it's not clear what encoding is, but that's a different matter.)
Note that your Equals override will also throw a NullReferenceException if ob is a non-null reference, but not to a BencodeString.
EDIT: Assuming you're actually wanting to check for the byte arrays being the same, I wouldn't call Encoding.GetString in your equality check. There's no point. Just check the byte array contents directly. Something like this is a reasonable byte array equality check - although I'd generally prefer to write a generic equivalent:
private static bool ArraysEqual(byte[] x, byte[] y)
{
if (x == y)
{
return true;
}
if (x == null || y == null)
{
return false;
}
if (x.Length != y.Length)
{
return false;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i])
{
return false;
}
}
return true;
}
If you do want to check whether two byte arrays are decoded to equal strings, then you should use Encoding.GetString in both places... but that would rarely be an appropriate thing to do, IMO.
Mind you, it's not clear why you've got your own string-like class to start with. There are all kinds of potential problems here... unequal encodings, null references etc.
It is very important that values that are Equal also produce the same hash code. An obvious (but not necessarily efficient) workaround is this:
public override int GetHashCode()
{
return encoding.GetString(this.str).GetHashCode();
}
Making strings not behave as Unicode strings internally is a a code smell but possibly intentional here. It is normally applied at the outer interface. Your implementation would allow for the encoding to change after the string is read. But a really serious problem with that is that the dictionary is no longer valid when that happens. You won't be able to find keys back.

Categories

Resources