C# Reflection Property.GetValue() Problem - c#

I am having a problem with the following code:
int errorCount = 0;
foreach (var cinf in client.GetType().GetProperties())
{
var vinf = viewModel.GetType().GetProperty(cinf.Name);
if (vinf != null)
{
if (cinf.GetValue(client, null) != vinf.GetValue(viewModel, null))
{
errorCount++;
}
}
}
It's for an automated test to see whether mapping a model object from a DTO has worked. If I use the more cumbersome approch of writing this for each property:
Assert.AreEqual(viewModel.ClientCompanyID, client.ClientCompanyID);
This works fine.
The problem is: the reflection code evaluates "if val1 != val2" statement incorrectly (or so it seems). If I step through this code, the evaluation basically says "1 does not equal 1", and incorrectly adds an error. Furthermore, if I test this with this code, I get the same seemingly false result:
var clientEx = client.GetType().GetProperty("ClientCompanyID");
var viewModelEx = viewModel.GetType().GetProperty("ClientCompanyID");
var clientVal = clientEx.GetValue(client, null);
var viewModelVal = viewModelEx.GetValue(viewModel, null);
bool test = (clientVal == viewModelVal);
The bool returns false even when, stepping through the code, clientVal = 1 and viewModelVal = 1. See attached picture.
Any help with this would be greatly appreciated!
Thanks guys.
Tim.
EDIT: Could have given you all the answer. Glad it was simple in the end. Thanks alot for your help. Cheers.

You need to compare with object.Equals() instead of using reference equality. Boxed value types will not compare as equal without using object.Equals(). Try this:
if (!object.Equals(cinf.GetValue(client, null), vinf.GetValue(viewModel, null)))
For example, take this simple case:
csharp> object a = 1;
csharp> object b = 1;
csharp> a == b;
false
csharp> object.Equals(a, b);
true

You're comparing to different boxed integers by reference.
Change it to
if (!Equals(cinf.GetValue(client, null), vinf.GetValue(viewModel, null))
This calls the static Object.Equals method, which will call the virtual Object.Equals method (after checking for null) to compare objects by value.
You'll see the same issue for strings.

This is only natural. If you compare to objects together using ==, it will compare their reference which is different.
Use objectA.Equals(objectB).

Related

Seemingly identical primitive values aren't equal

A strange case popped up. Two properties of two objects are being cast to the same primitive type and (seemingly) have the same value. However, the equality comparer returns false. If we use the Equals method (or other means of comparing the two values), then we get the correct result.
Even stranger, actually placing the result of the cast into a new variable also seems to works.
Below is a VERY simplified code example and and it will NOT yield the same results when copied and compiled. It's just used to illustrate the general setting where the problem occurs.
class Program
{
static void Main(string[] args)
{
var v1 = new Object1 { SomeValue = (short)-1d };
var invalidResult = (int)v1.SomeValue == (int)SomeEnum.Value1; //for some reason this returns false
var validResult = ((int)v1.SomeValue).CompareTo((int)SomeEnum.Value1) == 0; //this works
var extraValidResult = ((int)v1.SomeValue).Equals((int)SomeEnum.Value1);
var cast1 = (int)v1.SomeValue;
var cast2 = (int)SomeEnum.Value1;
var otherValidResult = cast1 == cast2; //this also works
}
}
public class Object1
{
public short SomeValue { get; set; }
}
public enum SomeEnum : short
{
Value1 = -1,
Value2 = 0,
Value3 = 1
}
Here's a screenshot of the VS watch window as proof of what we're seeing:
I know sometimes VS can show invalid values in the "watches" window, however the effects aren't limited to that window and a case actually fails an if check where it should not in one of our tests. AFAIK there's no trickery in the code (like overriding == or Equals).
What could possibly be happening here?
(We've obviously "fixed" the issue using the CompareTo method, but we're all still scratching our heads wondering what exactly had happened...)
EDIT:
I realize the code example above is... a tad bit useless. However posting the actual code in question might prove to be very difficult; there's a lot of it. Finally, the "live" values of some objects are populated from a SQL server (using Entity Framework), which complicates sharing of the code even further. I'm happy to try and answer any additional questions to try and narrow down the issue, but sharing of the FULL code is, unfortunately, not possible (a specific block of it is possible, but it won't compile for obvious reasons). The example code was provided to show how strange the issue is.
EDIT 2:
Sorry for the delay. Here's the particular method in question:
public bool IsLocalizationBlockedByMagPElem(int localizationId)
{
IEnumerable<MagPElem> magPElems = MagPElemRepository.GetByLocalizationIdAndStatusesOrderedByIdDescThenSubLpAsc(localizationId, DocumentStatus.InBuffer, DocumentStatus.InBufferReedition);
if (magPElems.Count() != 0)
{
var magPElem = magPElems.First();
//this commented out code did not return the expected value due to the strange comparison issue
//return (magPElem.MaP_GIDTyp == (int)ExternalSystemType.PM_GIDTyp || (magPElem.MaP_GIDTyp == (int)ExternalSystemType.MP_GIDTyp && magPElem.MaP_SubGIDLp == (short)LocalizationDirection.Destination));
//to avoid the issue CompareTo is being used, but Equals would work just as well
return (magPElem.MaP_GIDTyp == (int)ExternalSystemType.PM_GIDTyp || (magPElem.MaP_GIDTyp == (int)ExternalSystemType.MP_GIDTyp && magPElem.MaP_SubGIDLp.CompareTo((short)LocalizationDirection.Destination) == 0));
}
return false;
}
I've also updated the proof screenshot to encompass more of the screen. In the screenshot there are some minor discrepancies with the above code as we were testing to see what's going on (like trying out different casts or assigning the cast result to a variable). But the gist of the problem is there.

bugs in java code after converting from C#

here is a function prints repeating int in a array.
in c#:
int [] ReturnDups(int[] a)
{
int repeats = 0;
Dictionary<int, bool> hash = new Dictionary<int>();
for(int i = 0; i < a.Length i++)
{
bool repeatSeen;
if (hash.TryGetValue(a[i], out repeatSeen))
{
if (!repeatSeen)
{
hash[a[i]] = true;
repeats ++;
}
}
else
{
hash[a[i]] = false;
}
}
int[] result = new int[repeats];
int current = 0;
if (repeats > 0)
{
foreach(KeyValuePair<int,bool> p in hash)
{
if(p.Value)
{
result[current++] = p.Key;
}
}
}
return result;
}
now converted to JAVA by Tangible software's tool.
in java:
private int[] ReturnDups(int[] a)
{
int repeats = 0;
java.util.HashMap<Integer, Boolean> hash = new java.util.HashMap<Integer>();
for (int i = 0; i < a.length i++)
{
boolean repeatSeen = false;
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
{
if (!repeatSeen)
{
hash.put(a[i], true);
repeats++;
}
}
else
{
hash.put(a[i], false);
}
}
int[] result = new int[repeats];
int current = 0;
if (repeats > 0)
{
for (java.util.Map.Entry<Integer,Boolean> p : hash.entrySet())
{
if (p.getValue())
{
result[current++] = p.getKey();
}
}
}
return result;
}
but findbug find this line of code as bugs. and it looks very odd to me too.
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
can someone pls explain to me what this line does and how do i write it in java properly?
thanks
You have overcomplicated the code for TryGetValue - this simple translation should work:
if ( hash.containsKey(a[i]) ) {
if (!hash.get(a[i])) {
hash.put(a[i], true);
}
} else {
hash.put(a[i], false);
}
C# has a way to get the value and a flag that tells you if the value has been found in a single call; Java does not have a similar API, because it lacks an ability to pass variables by reference.
Do not directly convert C# implementation. assign repeatSeen value only if the id is there.
if (hash.containsKey(a[i]))
{
repeatSeen = hash.get(a[i]).equals(repeatSeen)
if (!repeatSeen)
{
hash.put(a[i], true);
repeats++;
}
}
To answer the actual question that was asked:
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen : false)
is indeed syntactically wrong. I haven't looked at the rest of the code, but having written parsers/code-generators in my time I'm guessing it was supposed to be
if (hash.containsKey(a[i]) ? (repeatSeen = hash.get(a[i])) == repeatSeen) : false)
It's gratuitously ugly -- which often happens with code generators, especially ones without an optimizing pass -- but it's syntactically correct. Let's see if it actually does have a well-defined meaning.
CAVEAT: I haven't crosschecked this by running it -- if someone spots an error, please tell me!
First off, x?y:z is indeed a ternary operator, which Java inherited from C via C++. It's an if-then-else expression -- if x is true it has the value y, whereas if x is false it has the value z. So this one-liner means the same thing as:
boolean implied;
if (hash.containsKey(a[i]) then
implied = (repeatSeen = hash.get(a[i])) == repeatSeen);
else
implied = false;
if(implied)
... and so on.
Now, the remaining bit of ugliness is the second half of that and-expression. I don't know if you're familiar with the use of = (assignment) as an expression operator; its value as an operator is the same value being assigned to the variable. That's mostly intended to let you do things like a=b=0;, but it can also be used to set variables "in passing" in the middle of an expression. Hardcore C hackers do some very clever, and ugly, things with it (he says, being one)... and here's it's being used to get the value from the hashtable, assign it to repeatSeen, and then -- via the == -- test that same value against repeatSeen.
Now the question is, what order are the two arguments of == evaluated in? If the left side is evaluated first, the == must always be true because the assignment will occur before the right-hand side retrieves the value. If the right side is evaluated first, we'd be comparing the new value against the previous value, in an very non-obvious way.
Well, in fact, there's another StackOverflow entry which addresses that question:
What are the rules for evaluation order in Java?
According to that, the rule for Java is that the left argument of an operator is always evaluated before the right argument. So the first case applies, the == always returns true.
Rewriting our translation one more time to reflect that, it turns into
boolean implied;
if (hash.containsKey(a[i]) then
{
repeatSeen = hash.get(a[i]));
implied = true;
}
else
implied = false;
if(implied)
Which could be further rewritten as
if (hash.containsKey(a[i]) then
{
repeatSeen = hash.get(a[i]));
// and go on to do whatever else was in the body of the original if statement
"If that's what they meant, why didn't they just write it that way?" ... As I say, I've written code generators, and in many cases the easiest thing to do is just make sure all the fragments you're writing are individually correct for what they're trying to do and not worry about whether they at all resemble what a human would have written do do the same thing. In particular, it's tempting to generate code according to templates which allow for cases you may not actually use, rather than trying to recognize the simpler situation and generate code differently.
I'm guessing that the compiler was drawing in and translating bits of computation as it realized it needed them, and that this created the odd nesting as it started the if, then realized it needed a conditional assignment to repeatSeen, and for whatever reason tried to make that happen in the if's test rather than in its body. Believe me, I've seen worse kluging from code generators.

Referring to an object defined by a variable

I have a problem, which I couldn't solve recently.
I have this code
foreach (Hashtable i in (ArrayList)inv["database"])
{
if (i != null)
{
if (i["type"].ToString() == "1")
{
if (i["dataValue"].ToString() != "0")
{
inv{nn}.Image = Program.Properties.Resources._i["type"].ToString()+"-"+i["dataValue"].ToString();
}
else
{
inv{nn}.Image = Program.Properties.Resources._i["type"].ToString()
}
}
}
nn++;
}
I have 36 controls(it's a class i have in my project, so not "vanilla" one), and each one of them is a single "picturebox". I have 505 images in the following syntax:
If the data value is 0, then it's {typeID}.png, if the data value is above 0, then {typeID}-{dataValue}.png
So for example if it's the first loop, i["type"].ToString() = 1 and i["dataValue"].ToString() = 3, the Image of inv0 changes to Program.Proporties.Resources._1-3
When the second loop comes the image of inv1 changes etc. ... till inv35
Is such thing possible? I tried
InterpolationBox x = Form1.FindControl("inv"+nn)
and I seem not to have such thing as FindControl (FrameWork 4) with System.Web.UI used.
I tried
InterpolationBox x = this.Controls.Find("inv" + nn, false);
And I got Unable to cast object of type 'System.Windows.Forms.Control[]' to type 'Program.InterpolatedBox'. And anyway, if I'd get rid of that error, would I be able to change that actual picturebox, not just the copied 'x' one?
InterpolationBox x = this.Controls.Find("inv" + nn, false);
Is where your problem lies.
The error you got is telling:
Unable to cast object of type 'System.Windows.Forms.Control[]' to type
'Program.InterpolatedBox'.
You can see it's saying it can't cast an array of System.Windows.Forms.Control to a Program.InterpolationBox which is sensible given InterpolationBox is a single control.
The Find method returns an array of controls, not just one, so you need to then look in the array and pull out the one you're after (even if it's just the first one).
As for your question about whether changing x would change the control you got given using Controls.Find() the answer is YES.
Objects in .NET are by reference, which means x isn't an InterpolationBox it's a reference to an InterpolationBox in memory.
You could even do:
var a = x;
var b = a;
var c = b;
c.DoSomething();
The code you call against c will operate against the same object, they're all just references pointing to the same thing.

Is List.Find<T> considered dangerous? What's a better way to do List<T>.Find(Predicate<T>)?

I used to think that List<T> is considered dangerous. My point is that, I think default(T) is not a safe return value! Many other people think so too Consider the following:
List<int> evens = new List<int> { 0, 2, 4, 6, , 8};
var evenGreaterThan10 = evens.Find(c=> c > 10);
// evenGreaterThan10 = 0 #WTF
default(T) for value types is 0, hence 0 is goona be returned is the above code segment!
I didn't like this, so I added an extension method called TryFind that returns a boolean and accepts an output parameter besides the Predicate, something similar to the famous TryParse approach.
Edit:
Here's my TryFind extension method:
public static bool TryFind<T>(this List<T> list, Predicate<T> predicate, out T output)
{
int index = list.FindIndex(predicate);
if (index != -1)
{
output = list[index];
return true;
}
output = default(T);
return false;
}
What's a your way to do Find on generic Lists?
I don't. I do .Where()
evens.Where(n => n > 10); // returns empty collection
evens.Where(n => n > 10).First(); // throws exception
evens.Where(n => n > 10).FirstOrDefault(); // returns 0
The first case just returns a collection, so I can simply check if the count is greater than 0 to know if there are any matches.
When using the second, I wrap in a try/catch block that handles InvalidOperationException specfically to handle the case of an empty collection, and just rethrow (bubble) all other exceptions. This is the one I use the least, simply because I don't like writing try/catch statements if I can avoid it.
In the third case I'm OK with the code returning the default value (0) when no match exists - after all, I did explicitly say "get me the first or default" value. Thus, I can read the code and understand why it happens if I ever have a problem with it.
Update:
For .NET 2.0 users, I would not recommend the hack that has been suggested in comments. It violates the license agreement for .NET, and it will in no way be supported by anyone.
Instead, I see two ways to go:
Upgrade. Most of the stuff that runs on 2.0 will run (more or less) unchanged on 3.5. And there is so much in 3.5 (not just LINQ) that is really worth the effort of upgrading to have it available. Since there is a new CLR runtime version for 4.0, there are more breaking changes between 2.0 and 4.0 than between 2.0 and 3.5, but if possible I'd recommend upgrading all the way to 4.0. There's really no good reason to be sitting around writing new code in a version of a framework that has had 3 major releases (yes, I count both 3.0, 3.5 and 4.0 as major...) since the one you're using.
Find a work-around to the Find problem. I'd recommend either just using FindIndex as you do, since the -1 that is returned when nothing is found is never ambiguous, or implementing something with FindIndex as you did. I don't like the out syntax, but before I write an implementation that doesn't use it, I need some input on what you want returned when nothing was found.
Until then, the TryFind can be considered OK, since it aligns with previous functionality in .NET, for example Integer.TryParse. And you do get a decent way to handle nothing found doing
List<Something> stuff = GetListOfStuff();
Something thing;
if (stuff.TryFind(t => t.IsCool, thing)) {
// do stuff that's good. thing is the stuff you're looking for.
}
else
{
// let the user know that the world sucks.
}
Instead of Find you could use FindIndex. It returns the index of the element found or -1 if no element was found.
http://msdn.microsoft.com/en-us/library/x1xzf2ca%28v=VS.80%29.aspx
It is ok if you know there are no default(T) values in your list or if the default(T) return value can't be the result.
You could implement your own easily.
public static T Find<T>(this List<T> list, Predicate<T> match, out bool found)
{
found = false;
for (int i = 0; i < list.Count; i++)
{
if (match(list[i]))
{
found = true;
return list[i];
}
}
return default(T);
}
and in code:
bool found;
a.Find(x => x > 5, out found);
Other options:
evens.First(predicate);//throws exception
evens.FindAll(predicate);//returns a list of results => use .Count.
It depends on what version of framework you can use.
If there is a problem with the default value of T, use Nullable to get a more meaningful default value :
List<int?> evens = new List<int?> { 0, 2, 4, 6, 8 };
var greaterThan10 = evens.Find(c => c > 10);
if (greaterThan10 != null)
{
// ...
}
This also requires no additional call of Exists() first.
Doing a call to Exists() first will help with the problem:
int? zz = null;
if (evens.Exists(c => c > 10))
zz = evens.Find(c => c > 10);
if (zz.HasValue)
{
// .... etc ....
}
slightly more long-winded, but does the job.
The same answer I gave on Reddit.
Enumerable.FirstOrDefault( predicate )
Inspired by Jaroslav Jandek above I would make an extension that returns bool true if match and passes the object in out if match:
static class Extension
{
public static bool TryFind<T>(this List<T> list, Predicate<T> match, out T founditem)
{
for (int i = 0; i < list.Count; i++)
{
if (match(list[i]))
{
founditem = list[i];
return true;
}
}
founditem = default(T);
return false;
}
}
Then it can used on a List object 'a' and called like this using 'out var' syntax:
if (a.TryFind(x => x > 5, out var founditem)){
//enter code here to use 'founditem'
};
Just for fun
evens.Where(c => c > 10)
.Select(c => (int?)c)
.DefaultIfEmpty(null)
.First();

Correct evaluation of expression

I came across the following expression in someone else's code. I think it's terrible code for a number of reasons (not least because it fails to take into account bool.TrueString and bool.FalseString), but am curious as to how the compiler will evaluate it.
private bool GetBoolValue(string value)
{
return value != null ? value.ToUpper() == "ON" ? true : false : false;
}
Edit
Incidentally, aren't the expressions evaluated from the inside-outwards? In this case, what's the point of checking for value != null after the call to value.ToUpper() which will throw a null reference exception?
I think the following is a correct (deliberately) verbose version (I'd never leave it like this :D ):
if (value != null)
{
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
}
else
{
return false;
}
Which can be shortened to:
return value != null && value.ToUpper == "ON";
Is this a correct re-writing of the expression?
It looks like the method is indended to handle a value that comes from a checkbox HTML element. If no value is specified for the checkbox, it uses the value "on" by default. If the checkbox is not checked there is no value at all from it in the form data, so reading the key from Request.Form gives a null reference.
In this context the method is correct, althought it's quite horrible due to the use of the if-condition-then-true-else-false anti-pattern. Also it should have been given a name that is more fitting for it's specific use, like GetCheckboxValue.
Your rewrite of the method is correct and sound. As the value is not culture dependant, converting the value to uppercase should not use the current culture. So a rewrite that is even slightly better than the one that you proposed would be:
return value != null && value.ToUpperInvariant == "ON";
(The culture independent methods are also a bit faster than the ones using a specific culture, so there is no reason not to use them.)
Incidentally, aren't the expressions
evaluated from the inside-outwards?
If it was method calls so that all expressions were actually evaluated, they would, as the inner call has to be made to evaluate the parameters for the outer call.
However, the second and third operands of the conditional expression is only evaluated if they are used, so the expressions are evaluated from the outside and inwards. The outermost condition is evaluated first to decide which of the operands it will evaluate.
You are correct, both in your rewriting and in your assertion that this attempt at conciseness is bad because it leads to confusion.
well the first one is a double-nested ternary operator
return (value != null) ? [[[value.ToUpper() == "ON" ? true : false]]] : false;
The bit in [[[ ]]] is the first result of the ternary expression which gets evaluated
when the first condition is true so you're reading/assertion of it is correct
but its ugly as hell and very unreadable/unmaintainable in its current state.
I'd definitely change it to your last suggestion
SideNote:
People who do
if(X == true)
return true;
else
return false;
instead of
return X;
should be taken out and shot ;-)
Are you looking for speed or readability and organization? Speed of execution, your shortened example is probably the best way to go.
For a few extra milliseconds, you could re-write this utility method as an extension method like so:
public static bool ToBoolean(this string value)
{
// Exit now if no value is set
if (string.IsNullOrEmpty(value)) return false;
switch (value.ToUpperInvariant())
{
case "ON":
case "TRUE":
return true;
}
return false;
}
... and then you would use it as follows:
public static void TestMethod()
{
bool s = "Test".ToBoolean();
}
EDIT:
Actually, I'm wrong... a quick performance test shows that the extension method is FASTER than the inline method. The source of my test is below, as well as the output on my PC.
[Test]
public void Perf()
{
var testValues = new string[] {"true", "On", "test", "FaLsE", "Bogus", ""};
var rdm = new Random();
int RunCount = 100000;
bool b;
string s;
Stopwatch sw = Stopwatch.StartNew();
for (var i=0; i<RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s.ToBoolean();
}
Console.Out.WriteLine("Method 1: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (var i = 0; i < RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s != null ? s.ToUpperInvariant() == "ON" ? true : s.ToUpperInvariant() == "TRUE" ? true : false : false;
}
Console.Out.WriteLine("Method 2: {0}ms", sw.ElapsedMilliseconds);
}
Output:
Method 1: 21ms
Method 2: 30ms
I read the original expression the same way you do. So I think your shortened expression is correct. If value is null it will never get to the second conditional, so it looks safe to me.
I also hate the constructs like:
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
as you noticed it is a long and convoluted (not to say stupid) way of writing:
return value.ToUpper() == "ON";
Your proposition is nice, short and correct.
Another alternative:
return string.Equals( value, "ON", StringComparison.OrdinalIgnoreCase );

Categories