Unable to debug GetHashCode method - c#

I have implemented a equality comparer in below manner.
class BoxEqualityComparer : IEqualityComparer<Box>
{
public bool Equals(Box b1, Box b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null | b2 == null)
return false;
else if(b1.Height == b2.Height && b1.Length == b2.Length
&& b1.Width == b2.Width)
return true;
else
return false;
}
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
Then I have created a Dictionary, in that I will add some values. So here it will compare object based on it's properties (height, width, length). I am getting the expected output. But I am wondering about the execution of GetHashCode method. I put a breakpoint in there, but I am unable to debug it. My question is when does GeHashCode method will be executed and how many times?
class Example
{
static void Main()
{
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
var boxes = new Dictionary<Box, string>(boxEqC);
var redBox = new Box(4, 3, 4);
AddBox(boxes, redBox, "red");
var blueBox = new Box(4, 3, 4);
AddBox(boxes, blueBox, "blue");
var greenBox = new Box(3, 4, 3);
AddBox(boxes, greenBox, "green");
Console.WriteLine();
Console.WriteLine("The dictionary contains {0} Box objects.",
boxes.Count);
}
private static void AddBox(Dictionary<Box, String> dict, Box box, String name)
{
try {
dict.Add(box, name);
}
catch (ArgumentException e) {
Console.WriteLine("Unable to add {0}: {1}", box, e.Message);
}
}
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
public override String ToString()
{
return String.Format("({0}, {1}, {2})", Height, Length, Width);
}
}

See https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,fd1acf96113fbda9.
Add(key, value) calls the insert method, which in turn will always calculate a hash code via
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
So in other words, each call to Dictionary.Add should always trigger a calculation of the key's hash via the IEqualityComparer you provided.
As for your example code, this works fine for me, VS 2015 does break at BoxEqualityComparer.GetHashCode() for me.

Related

Why Can't I implement generic method in C#?

I am trying to implement a simple generic method in c# that can convert from an NI ComplexSingle and NI ComplexDouble which are structs to a Complex as defined in System.Numerics, which is also a struct. Both
ComplexSingle and ComplexDouble have properties Real and Imaginary defined here:
public double Real
{
get
{
return _privateBackingFieldForProperty_Real;
}
set
{
double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
_privateBackingFieldForProperty_Real = value;
}
}
public double Imaginary
{
get
{
return _privateBackingFieldForProperty_Imaginary;
}
set
{
double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
_privateBackingFieldForProperty_Imaginary = value;
}
}
All I want to do is make a single function that can take in either a ComplexSingle array or ComplexDouble array and convert either one into a Complex array. I was hoping to do that by using a generic method as below. However, I soon realized that the Real and Imaginary properties could not be found because the generic passed in doesn't know about them. Then, I thought maybe I could use an interface, which I defined below that has the properties that are found in the actual struct. Now I am getting an error below at:
Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);
that
Code is below:
using NationalInstruments;
using System;
using System.Numerics;
namespace ComplexStuff
{
class ComplexMod
{
static void Main(string[] args)
{
Complex c1 = new Complex(4, 3);
Complex c2 = new Complex(5, 4);
Complex c3 = new Complex(6, 5);
ComplexDouble cd1 = new ComplexDouble(4, 3);
ComplexDouble cd2 = new ComplexDouble(4, 3);
ComplexDouble cd3 = new ComplexDouble(4, 3);
ComplexSingle cs1 = new ComplexSingle(7, 2);
ComplexSingle cs2 = new ComplexSingle(7, 2);
ComplexSingle cs3 = new ComplexSingle(7, 2);
ComplexDouble[] cd = new ComplexDouble[]{
cd1, cd2, cd3
};
Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);
}
public interface IComplexNI
{
public double Real { get; set; }
public double Imaginary { get; set; }
}
static Complex[] ComplexNItoComplex<T>(IList<T> NIComplex) where T : IComplexNI
{
Complex[] c = new Complex[NIComplex.Count];
for (int i = 0; i < NIComplex.Count; i++)
{
c[i] = new Complex(NIComplex[i].Real, NIComplex[i].Imaginary);
}
return c;
}
}
}
Complex Double:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security;
using NationalInstruments.Internal;
using NationalInstruments.Restricted;
namespace NationalInstruments
{
[Serializable]
[DebuggerDisplay("\\{{Real} + {Imaginary}i}")]
[TypeConverter(typeof(ComplexDoubleConverter))]
public struct ComplexDouble : IFormattable, ISerializable, IEquatable<ComplexDouble>
{
private const string RealKey = "Real";
private const string ImaginaryKey = "Imaginary";
private double _privateBackingFieldForProperty_Real;
private double _privateBackingFieldForProperty_Imaginary;
public double Magnitude => Math.Sqrt(Real * Real + Imaginary * Imaginary);
public double Phase => Math.Atan2(Imaginary, Real);
public static ComplexDouble Zero => new ComplexDouble(0.0, 0.0);
public ComplexDouble ComplexConjugate => new ComplexDouble(Real, 0.0 - Imaginary);
public double Real
{
get
{
return _privateBackingFieldForProperty_Real;
}
set
{
double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
_privateBackingFieldForProperty_Real = value;
}
}
public double Imaginary
{
get
{
return _privateBackingFieldForProperty_Imaginary;
}
set
{
double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
_privateBackingFieldForProperty_Imaginary = value;
}
}
public ComplexDouble(double real, double imaginary)
{
this = default(ComplexDouble);
Real = real;
Imaginary = imaginary;
}
public static ComplexDouble FromPolar(double magnitude, double phase)
{
return new ComplexDouble(magnitude * Math.Cos(phase), magnitude * Math.Sin(phase));
}
public static ComplexDouble FromDouble(double real)
{
return new ComplexDouble(real, 0.0);
}
public static explicit operator ComplexDouble(double real)
{
return FromDouble(real);
}
public override string ToString()
{
return ToString(null, null);
}
public string ToString(string format)
{
return ToString(format, null);
}
public string ToString(IFormatProvider formatProvider)
{
return ToString(null, formatProvider);
}
public string ToString(string format, IFormatProvider formatProvider)
{
string text = Real.ToString(format, formatProvider);
string text2 = Math.Abs(Imaginary).ToString(format, formatProvider);
NumberFormatInfo numberFormat = ComplexParser.GetNumberFormat(formatProvider);
string text3 = (Real.IsNegativeZero() ? numberFormat.NegativeSign : null);
string text4 = ((Imaginary < 0.0 || Imaginary.IsNegativeZero()) ? numberFormat.NegativeSign : numberFormat.PositiveSign);
return string.Format(CultureInfo.InvariantCulture, "{0}{1} {2} {3}i", text3, text, text4, text2);
}
public static ComplexDouble Parse(string input)
{
return Parse(input, null);
}
public static ComplexDouble Parse(string input, IFormatProvider provider)
{
if (input == null)
{
throw ExceptionBuilderBase.ArgumentNull("input");
}
if (!ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out var real, out var imaginary))
{
throw ExceptionBuilder.InvalidComplexDoubleFormat(input);
}
return new ComplexDouble(real, imaginary);
}
public static bool TryParse(string input, out ComplexDouble result)
{
return TryParse(input, null, out result);
}
public static bool TryParse(string input, IFormatProvider provider, out ComplexDouble result)
{
double real;
double imaginary;
bool result2 = ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out real, out imaginary);
result = new ComplexDouble(real, imaginary);
return result2;
}
public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData)
{
if (realData == null)
{
throw ExceptionBuilderBase.ArgumentNull("realData");
}
if (imaginaryData == null)
{
throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
}
int num = realData.Length;
if (num != imaginaryData.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
}
ComplexDouble[] array = new ComplexDouble[num];
for (int i = 0; i < num; i++)
{
array[i] = new ComplexDouble(realData[i], imaginaryData[i]);
}
return array;
}
public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData, int startIndex, int length)
{
if (realData == null)
{
throw ExceptionBuilderBase.ArgumentNull("realData");
}
if (imaginaryData == null)
{
throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
}
int num = realData.Length;
if (num != imaginaryData.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
}
if (startIndex < realData.GetLowerBound(0) || startIndex >= num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
}
if (length < 0 || startIndex + length > num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("length");
}
ComplexDouble[] array = new ComplexDouble[length];
int num2 = startIndex;
int num3 = 0;
while (num2 < startIndex + length)
{
array[num3] = new ComplexDouble(realData[num2], imaginaryData[num2]);
num2++;
num3++;
}
return array;
}
public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases)
{
if (magnitudes == null)
{
throw ExceptionBuilderBase.ArgumentNull("magnitudes");
}
if (phases == null)
{
throw ExceptionBuilderBase.ArgumentNull("phases");
}
int num = magnitudes.Length;
if (num != phases.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
}
ComplexDouble[] array = new ComplexDouble[num];
for (int i = 0; i < num; i++)
{
array[i] = FromPolar(magnitudes[i], phases[i]);
}
return array;
}
public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases, int startIndex, int length)
{
if (magnitudes == null)
{
throw ExceptionBuilderBase.ArgumentNull("magnitudes");
}
if (phases == null)
{
throw ExceptionBuilderBase.ArgumentNull("phases");
}
int num = magnitudes.Length;
if (num != phases.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
}
if (startIndex < magnitudes.GetLowerBound(0) || startIndex >= num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
}
if (length < 0 || startIndex + length > num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("length");
}
}
}
I know that the error only occurs if I have the real and imaginary properties in IComplexNI. I'm thinking I don't quite understand interfaces fully, since I was thinking that since I have Real and Complex defined in the interface, then the code would know to look for them when looking in the generic type. I guess that's wrong, though. I was guessing that you could reference the properties of objects or structs somehow in generic methods, but it sounds more complicated than what I was hoping..?
You can't write a single method to convert both types. Both types have a Real and an Imaginary property each, but the types of these properties are different.
The ComplexDouble type has Real and Imaginary properties of type double.
The ComplexSingle type has Real and Imaginary properties of type float.
The easiest solution is to use method overloading: You can have two methods with the same name and different parameter types. The compiler will then choose the correct method automatically based on the type of argument you pass to them:
static Complex[] ComplexNItoComplex(IEnumerable<ComplexDouble> NIComplex)
{
return (from c in NIComplex
select new Complex(c.Real, c.Imaginary))
.ToArray();
}
static Complex[] ComplexNItoComplex(IEnumerable<ComplexSingle> NIComplex)
{
return (from c in NIComplex
select new Complex(c.Real, c.Imaginary))
.ToArray();
}
Sample usage:
ComplexDouble cd1 = new ComplexDouble(4, 3);
ComplexDouble cd2 = new ComplexDouble(4, 3);
ComplexDouble cd3 = new ComplexDouble(4, 3);
ComplexSingle cs1 = new ComplexSingle(7, 2);
ComplexSingle cs2 = new ComplexSingle(7, 2);
ComplexSingle cs3 = new ComplexSingle(7, 2);
ComplexDouble[] cd = new ComplexDouble[]{
cd1, cd2, cd3
};
ComplexSingle[] cs = new ComplexSingle[]{
cs1, cs2, cs3
};
Complex[] complexes1 = ComplexNItoComplex(cd);
Complex[] complexes2 = ComplexNItoComplex(cs);

How to check if key exists in a dictionary when the key itself is a dictionary (C#)?

I have a dictionary[mapData] as below and check key is a [Dictionary< string, DateTime >] exists in [mapData], but it did not work:
var mapData = new Dictionary<Dictionary<string, DateTime>, List<Student>>();
foreach (var st in listStudent)
{
// Create Key
var dicKey = new Dictionary<string, DateTime>();
dicKey.Add(st.Name, st.Birthday);
// Get mapData
if (!mapData.ContainsKey(dicKey)) // ===> Can not check key exists
{
mapData.Add(dicKey, new List<Student>());
}
mapData[dicKey].Add(st);
}
I tried with extension method as the below, but also not work:
public static bool Contains<Tkey>(this Dictionary<Tkey, List<Student>> dic, Tkey key)
{
if (dic.ContainsKey(key))
return true;
return false;
}
Any tips on these will be great help. Thanks in advance.
this is because you try to find the key based on object reference not the key content.
Your dictionnary key is a composite of Key + value (string + DateTime) reference.
this wont work unless you rewrite and IEqualityComparer.
var objectA = new ObjectA();
var objectB = new ObjectA();
objectA != objectB unless you rewritte the equals.
EDIT
This sample is comming from MSDN https://msdn.microsoft.com/en-us/library/ms132151(v=vs.110).aspx
using System;
using System.Collections.Generic;
class Example
{
static void Main()
{
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
var boxes = new Dictionary<Box, string>(boxEqC);
var redBox = new Box(4, 3, 4);
AddBox(boxes, redBox, "red");
var blueBox = new Box(4, 3, 4);
AddBox(boxes, blueBox, "blue");
var greenBox = new Box(3, 4, 3);
AddBox(boxes, greenBox, "green");
Console.WriteLine();
Console.WriteLine("The dictionary contains {0} Box objects.",
boxes.Count);
}
private static void AddBox(Dictionary<Box, String> dict, Box box, String name)
{
try {
dict.Add(box, name);
}
catch (ArgumentException e) {
Console.WriteLine("Unable to add {0}: {1}", box, e.Message);
}
}
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
public override String ToString()
{
return String.Format("({0}, {1}, {2})", Height, Length, Width);
}
}
class BoxEqualityComparer : IEqualityComparer<Box>
{
public bool Equals(Box b1, Box b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null | b2 == null)
return false;
else if(b1.Height == b2.Height && b1.Length == b2.Length
&& b1.Width == b2.Width)
return true;
else
return false;
}
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
// The example displays the following output:
// Unable to add (4, 3, 4): An item with the same key has already been added.
//
// The dictionary contains 2 Box objects.
You don't want to go there. Complex objects are not meant to be keys in a dictionary. I would suggest to move the dictionary to the value and create a more tree-like structure.
There is one possibility to get this working, but I would advice against it for above reasons: the implementation of a custom IEqualityComparer which compares the keys in the dictionary against another dictionary.

Slow dictionary with custom class key

I have a custom class that I was trying to use as a key for a dictionary:
// I tried setting more than enough capacity also...
var dict = new Dictionary<MyPoint, MyPoint>(capacity);
Now let me be clear, the goal here is to compare two SIMILAR but DIFFERENT lists, using X, Y, and Date as a composite key. The values will vary between these two lists, and I'm trying to quickly compare them and compute their differences.
Here is the class code:
public class MyPoint : IEquatable<MyPoint>
{
public short X { get; set; }
public short Y { get; set; }
public DateTime Date { get; set; }
public double MyValue { get; set; }
public override bool Equals(object obj)
{
return base.Equals(obj as MyPoint);
}
public bool Equals(MyPoint other)
{
if (other == null)
{
return false;
}
return (Date == other.Date)
&& (X == other.X)
&& (Y == other.Y);
}
public override int GetHashCode()
{
return Date.GetHashCode()
| X.GetHashCode()
| Y.GetHashCode();
}
}
I also tried keying with a struct:
public struct MyPointKey
{
public short X;
public short Y;
public DateTime Date;
// The value is not on these, because the struct is only used as key
}
In both cases dictionary writing was very, very slow (reading was quick).
I changed the key to a string, with the format:
var dict = new Dictionary<string, MyPoint>(capacity);
var key = string.Format("{0}_{1}", item.X, item.Y);
I was amazed at how much quicker this is -- it's at least 10 times faster. I tried Release mode, no debugger, and every scenario I could think of.
This dictionary will contain 350,000 or more items, so performance does matter.
Any thoughts or suggestions? Thanks!
Another edit...
I'm trying to compare two lists of things in the fastest way I can. This is what I'm working with. The Dictionary is important for fast lookups against the source list.
IList<MyThing> sourceList;
IDictionary<MyThing, MyThing> comparisonDict;
Parallel.ForEach(sourceList,
sourceItem =>
{
double compareValue = 0;
MyThing compareMatch = null;
if (comparisonDict.TryGetValue(sourceItem, out compareMatch))
{
compareValue = compareMatch.MyValue;
}
// Do a delta check on the item
double difference = sourceItem.MyValue- compareValue;
if (Math.Abs(difference) > 1)
{
// Record the difference...
}
});
As others have said in the comments, the problem is in your GetHashCode() implementation. Taking your code, and running 10,000,000 iterations with the string key took 11-12 seconds. Running with your existing hashCode I stopped it after over a minute. Using the following hashCode implementation took under 5 seconds.
public override int GetHashCode()
{
var hashCode = Date.GetHashCode();
hashCode = (hashCode * 37) ^ X.GetHashCode();
hashCode = (hashCode * 37) ^ Y.GetHashCode();
return hashCode;
}
The problem is that when you get into large numbers, the items are all colliding in the same buckets, due to the ORs. A dictionary where everything is in the same bucket is just a list.
If I got you right, you like to use a set while still maintaining the order of the keys. In this case, take SortedSet`1 instead.
Code:
class Program {
static void Main(string[] args) {
SortedSet<MyKey> list = new SortedSet<MyKey>() {
new MyKey(0, 0, new DateTime(2015, 6, 4)),
new MyKey(0, 1, new DateTime(2015, 6, 3)),
new MyKey(1, 1, new DateTime(2015, 6, 3)),
new MyKey(0, 0, new DateTime(2015, 6, 3)),
new MyKey(1, 0, new DateTime(2015, 6, 3)),
};
foreach(var entry in list) {
Console.WriteLine(string.Join(", ", entry.X, entry.Y, entry.Date));
}
Console.ReadKey();
}
}
I changed your MyPoint class as follows:
public sealed class MyKey : IEquatable<MyKey>, IComparable<MyKey> {
public readonly short X;
public readonly short Y;
public readonly DateTime Date;
public MyKey(short x, short y, DateTime date) {
this.X = x;
this.Y = y;
this.Date = date;
}
public override bool Equals(object that) {
return this.Equals(that as MyKey);
}
public bool Equals(MyKey that) {
if(that == null) {
return false;
}
return this.Date == that.Date
&& this.X == that.X
&& this.Y == that.Y;
}
public static bool operator ==(MyKey lhs, MyKey rhs) {
return lhs != null ? lhs.Equals(rhs) : rhs == null;
}
public static bool operator !=(MyKey lhs, MyKey rhs) {
return lhs != null ? !lhs.Equals(rhs) : rhs != null;
}
public override int GetHashCode() {
int result;
unchecked {
result = (int)X;
result = 31 * result + (int)Y;
result = 31 * result + Date.GetHashCode();
}
return result;
}
public int CompareTo(MyKey that) {
int result = this.X.CompareTo(that.X);
if(result != 0) {
return result;
}
result = this.Y.CompareTo(that.Y);
if(result != 0) {
return result;
}
result = this.Date.CompareTo(that.Date);
return result;
}
}
Output:
0, 0, 03.06.2015 00:00:00
0, 0, 04.06.2015 00:00:00
0, 1, 03.06.2015 00:00:00
1, 0, 03.06.2015 00:00:00
1, 1, 03.06.2015 00:00:00

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
}

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