patterncsharpMinor
Unusual comparison of object and string
Viewed 0 times
unusualcomparisonandobjectstring
Problem
I have a pretty unusual situation (please, don't ask why) where I need to compare objects which might be a
To make it clear what I expect to get from that function:
string or double to string which might be a string or a double.ToString(). I've come up with something which I really don't like, so please feel free to criticize it and suggest a better solution.public bool AreEqual(string stringValue, object objectValue)
{
double numericValue;
return (stringValue == (objectValue ?? string.Empty).ToString()) || // trying to compare values as strings
(double.TryParse(stringValue, out numericValue) && (numericValue == objectValue as double?)); // otherwise - as double
}To make it clear what I expect to get from that function:
[TestCase("a", "a", true)]
[TestCase("a", "b", false)]
[TestCase("10", 10, true)]
[TestCase("11", 10, false)]
[TestCase("11", "11.0", true)]
[TestCase("11", "11.5", false)]
public void ComparisionTest(string stringValue, object objectValue, bool areEqual)
{
bool result = AreEqual(stringValue, objectValue);
Assert.That(result == areEqual)
}Solution
Your clarification made it a lot clearer what you want. I think you're trying too much to make it all fit on two lines and you can make it must more readable by splitting it out a little.
Following straightforward logic (really just translating your description) I came to this which works for all 4 tests (note that argument
Note that you can also use a direct cast instead of
Note that I also use
I have made changes that take care of the added test cases which you specified later. Alongside that it also takes care of the culture-specific notation (dot vs comma) and floating point errors.
It's more lengthy than your solution but it is also more robust code and a lot easier to digest.
This takes care of the following testcases:
Following straightforward logic (really just translating your description) I came to this which works for all 4 tests (note that argument
10 is an integer, not a double).public bool AreEqual(string stringValue, object objectValue)
{
if (objectValue is string)
{
double parsedValue;
if (double.TryParse(objectValue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out parsedValue))
{
return Math.Abs(double.Parse(stringValue, CultureInfo.InvariantCulture) - parsedValue) < 0.00000001;
}
return stringValue == objectValue as string;
}
if (objectValue is double)
{
return double.Parse(stringValue, CultureInfo.InvariantCulture) == objectValue as double?;
}
throw new ArgumentException("The object must either be a string or a double");
}Note that you can also use a direct cast instead of
as since it is guaranteed to be a possible cast, but I like to read as myself (the performance impact is minimal and not relevant in our scenario).Note that I also use
double.Parse instead of double.TryParse because from your description I can assume it is either a double or a string. If it isn't, I'm throwing an exception anyway at the end so I don't feel compelled to use TryParse.I have made changes that take care of the added test cases which you specified later. Alongside that it also takes care of the culture-specific notation (dot vs comma) and floating point errors.
It's more lengthy than your solution but it is also more robust code and a lot easier to digest.
This takes care of the following testcases:
AreEqual("a", "a") // true
AreEqual("a", "b") // false
AreEqual("10", 10.0) // true
AreEqual("11", 10.0) // false
AreEqual("11", "11.0") // true
AreEqual("11", "11.5") // false
AreEqual("11.0", "11") // trueCode Snippets
public bool AreEqual(string stringValue, object objectValue)
{
if (objectValue is string)
{
double parsedValue;
if (double.TryParse(objectValue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out parsedValue))
{
return Math.Abs(double.Parse(stringValue, CultureInfo.InvariantCulture) - parsedValue) < 0.00000001;
}
return stringValue == objectValue as string;
}
if (objectValue is double)
{
return double.Parse(stringValue, CultureInfo.InvariantCulture) == objectValue as double?;
}
throw new ArgumentException("The object must either be a string or a double");
}AreEqual("a", "a") // true
AreEqual("a", "b") // false
AreEqual("10", 10.0) // true
AreEqual("11", 10.0) // false
AreEqual("11", "11.0") // true
AreEqual("11", "11.5") // false
AreEqual("11.0", "11") // trueContext
StackExchange Code Review Q#61306, answer score: 5
Revisions (0)
No revisions yet.