简体   繁体   中英

Why ExpandoObject doesn't work properly with Guid converted to string?

I have a piece of code that works properly if you pass two strings. For some reason it doesn't work the same if you pass GUID converted to string.

In more details, if I create a new ExpandoObject and pass string value it works but if I pass GUID converted to string it doesn't.

The code below should compare two parameters. In my example I pass the same two strings. With Equal operator it should return true if the strings are the same. If second parameter GUID converted to string it returns false even strings are the same. dynamicObj.Add(memberName, Guid.Parse(value).ToString());

Not sure what I'm missing. Here is my code.

 string value = "642188c7-8e10-e111-961b-0ee1388ccc3b";

 string memberName = "State";
 string contactValue = value;

 var dynamicObj = (IDictionary<string, object>)new ExpandoObject();   dynamicObj.Add(memberName, Guid.Parse(value).ToString());

 var expression = Expression.Parameter(typeof(object), "arg");
 var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });

 var property = Expression.Dynamic(binder, typeof(object), expression);

 var isValid = false;
 var right = Expression.Constant(contactValue);
 var result = Expression.MakeBinary(ExpressionType.Equal, property, right);
 var func = typeof(Func<,>).MakeGenericType(dynamicObj.GetType(), typeof(bool));
 var expr = Expression.Lambda(func, result, expression).Compile();

 isValid = (bool)expr.DynamicInvoke(dynamicObj);

The GUID parsing will end up with the same string (value) as just using a string literal.

The difference however is the way it is stored in the dictionary: it's of type Dictionary<string, object> . This means that the Object class its == operator will be used which does a reference equality check. The String class, however, overloads this by doing a value equality check.

That's why this returns true:

Console.WriteLine(value == Guid.Parse(value).ToString());

While this returns false:

Console.WriteLine((object) value == (object) Guid.Parse(value).ToString());

Since strings are immutable, Guid.Parse(value).ToString() will create a new string object and do a reference equality check compared with contactValue (which is the same as value ). This will evidently return false compared to using value all along which returns true because you never create a new object.

In order to make it work you can just cast the dynamic operand to a string so it will use the correct overload:

var castDyn = Expression.Convert(property, typeof(string));
var result = Expression.MakeBinary(ExpressionType.Equal, castDyn, right);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM