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

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

Related

Comparing different types in Expression Trees

In my API I give the option to filter the result - similar to the SQL statement WHERE. This works if I use a string field and compare this with a string value:
https://apiurl/items?filterfieldname=name&filterfieldvalue=test
Now I only get back items where the name is "test"
However, if I want to apply this to a bool field (in this case, called "isActive"), to return only active items:
https://apiurl/items?filterfieldname=isActive&filterfieldvalue=true
Then I get the following exception:
System.InvalidOperationException: 'The binary operator Equal is not defined for the types 'System.Nullable`1[System.Boolean]' and 'System.String'.'
I use the following code to create the expression:
static Expression<Func<T, bool>> GetExpressionForFilter<T>(string propertyName, string propertyValue)
{
var nameForWhereClause = propertyName.ToLowerInvariant();
var valueForWhereClause = propertyValue.Trim().ToLowerInvariant();
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameterExp, nameForWhereClause);
ConstantExpression someValue = Expression.Constant(valueForWhereClause, typeof(string));
return Expression.Lambda<Func<T, bool>>(Expression.Equal(propertyExp, someValue), parameterExp);
}
And apply the expression to my collection:
var condition = GetExpressionForFilter<TEntity>(entitiesResourceParameters.FilterFieldName, entitiesResourceParameters.FilterFieldValue);
condition.Compile();
var collectionAfterFilter = collectionBeforeFilter.Where(condition).AsQueryable();
I tried to convert the property type to a string before comparing it to a "true" or "false" string, but this made no difference.
I would like to be able to enter any type of field (including boolean) and compare this with the value (as string) of this field (for example, "true" or "false"). Is this possible?
You can convert the string value into the type you're trying to compare it with.
var propertyType = property.PropertyType;
var value = Convert.ChangeType(valueForWhereClause, propertyType);
ConstantExpression someValue = Expression.Constant(value, propertyType);
Be aware that Convert.ChangeType can throw an exception if an invalid value is provided (e.g. &filterfieldvalue=foo).

Compare types if one is nullable

I need to check if two types are the same:
private bool AreOfTheSameType(object obj1, object obj2) {
return obj1.GetType()==obj2.GetType();
}
This works fine with this values:
var test1=AreOfTheSameType(new DateTime(), new DateTime()) // true;
var test2=AreOfTheSameType(new int(), new DateTime()) // false;
What I now want is that the following returns true, too:
var test3=AreOfTheSameType(new int?(), new int())
So if the types have the same base, but one is nullable, the other isn't, I also want to return it as true. Or to say it in another way I want to have a function that returns whether I can store obj1 into obj2 directly using reflection without having to cast the value.
UPDATE
I reduced my code to make it more readable. Looks like this time that was contra-productive. The real-world-code follows:
var entity = Activator.CreateInstance(typeof(T));
Type entityType = typeof(T);
PropertyInfo[] entityProperties = entityType.GetProperties();
foreach (KeyValuePair<string, object> fieldValue in item.FieldValues)
{
if (fieldValue.Value == null) continue;
var property = entityProperties.FirstOrDefault(prop => prop.Name == fieldValue.Key);
if (property != null && property.CanWrite)
{
Type valueType = fieldValue.Value.GetType();
if (fieldValue.Value.GetType() == property.PropertyType) {
// Assign
}
}
}
The problem on the "//Assign" - line is, I have the following two types:
fieldValue.Value.GetType().ToString()="System.DateTime"
property.PropertyType.ToString()="System.Nullable`1[System.DateTime]"
which are obiously not the same but could be assigned
which are obiously not the same but could be assigned
It looks like you're after the Type.IsAssignableFrom method:
var dt = typeof(DateTime);
var nd = typeof(DateTime?);
Console.WriteLine(dt.IsAssignableFrom(nd)); // false
Console.WriteLine(nd.IsAssignableFrom(dt)); //true
Live example: http://rextester.com/KDOW15238
Calling GetType on nullable types returns the original type:
int? i = 5;
Type t = i.GetType();
Console.WriteLine(t.FullName); //"System.Int32"
So AreOfTheSameType((int?)5, 5) should return true.
But as soon as you box a Nullable<T>, you either get null (if Nullable<T>.HasValue was false), or you get the boxed underlying value, losing the "nullable" part. So the problem you're facing here is that new int? will be boxed into a null object when passed to the method.
The problem with nullable types is that empty values box to null, and once they're null, you cannot find out what they were. The only way to solve this, then, is with generics:
private bool AreOfTheSameType<T1,T2>(T1 obj1, T2 obj2) {
// get the types as best we can determine
var t1 = obj1?.GetType() ?? typeof(T1);
var t2 = obj2?.GetType() ?? typeof(T2);
// Nullable<T> => T
t1 = Nullable.GetUnderlyingType(t1) ?? t1;
t2 = Nullable.GetUnderlyingType(t2) ?? t2;
// compare
return t1 == t2;
}
This will use the object if available (to allow for subclasses etc), but will fall back to typeof if the object is null - which means it should work for int? etc... as long as the type of the expression being passed in wasn't object to begin with; if it was object and the value is null, then... you're out of luck - you can't ever find out the original type. By which I mean:
This should be fine:
var test3=AreOfTheSameType(new int?(), new int());
But this will fail:
object x = new int?(), y = new int();
var test4=AreOfTheSameType(x, y);

Accessing Type T property in the ParameterExpression type Dictionary<string,T>

I have expression tree code used for data filtering, till date it was used on a Generic list List<T> and following code use to work fine:
var parameterType = Expression.Parameter(typeof(T), "obj");
var memberExpression = Expression.Property(parameterType, "Name");
It was easy to create a binary expression as follows and process the result:
var constantExpression = Expression.Constant("Jack",typeof(string));
var finalExpression = Expression.Equal(memberExpression,constantExpression);
var resultFunc = Expression.Lambda<Func<T, bool>>(finalExpression, parameterType).Compile();
// Final Result
sourceList.Where(obj => resultFunc(obj));
Here Name is a property in Type T, as result post Lambda compilation was Func<T,bool>, I use to apply the same to the Where clause of IEnumerable type. Now the underlying system has changed to use the same code on Dictionary<string,T>, so all the Type T values in the collection now have a string Key associated and type T is now accessible as a value of dictionary object. Also I am applying on a IQueryable, which takes an expression tree the final lambda post compilation at source would be Func<KeyValuePair<string,T>,bool>, therefore cannot apply the Value in the final result processing.
Following is the code modification now:
var parameterType = Expression.Parameter(typeof(KeyValuePair<string,T>), "obj");
Following code fails, since now Name property is in Value of the KeyValuePair and we cannot use it as Type T:
var memberExpression = Expression.Property(parameterType, "Name");
Any pointer to make it work or any suggestion to set me in the right direction?
You could get Expression for calling ["name"] item this way:
var nameProperty= Expression.Call(parameterType,
typeof(IDictionary<string, T>).GetMethod("get_Item"),
Expression.Constant("Name"));
or as:
var nameProperty = Expression.Property(parameterType, "Item",
new Expression[] { Expression.Constant("Name") });
Both is call of Item property
EDIT : To get Value from KeyValuePair you have to get property Key, compare it with "Name" and a property Value and compare it with value:
var parameterType = Expression.Parameter(typeof(KeyValuePair<string,T>), "obj");
var value = Expression.Property(parameterType, "Value" );
var key = Expression.Property(parameterType, "Key");
var eq1 = Expression.Equal(key, Expression.Constant("Name"));
var eq2 = Expression.Equal(value, constantExpression);
var and = Expression.And(eq1, eq2);
var lambda = Expression.Lambda(and, parameterType);

Expression.LessThan vs LambdaExpression<Func<ParamType,object>>

I've got a LambdaExpression which takes one object as a Parameter and ultimately returns an object.
For the purposes of testing, here's a Lambda (created longhand to match what i'm really passing in) that returns a DateTime boxed as an object.
For the purposes of working this through, the LambdaExpression takes an XmlNode and returns an object.
It must return an object, the real return type could be any of: DateTime,bool,int,decimal,XmlDocument [so far]
The general idea is that somewhere deep in a parser, this lambda is created and it extracts a value from it's input parameter and returns it typed, but boxed in an object.
XmlNode node = null;
ParameterExpression instanceExpression = Expression.Parameter(typeof(DynamicNode), "instance");
ParameterExpression result = Expression.Parameter(typeof(object), "result");
LabelTarget blockReturnLabel = Expression.Label(typeof(object));
BlockExpression block = Expression.Block(
typeof(object),
new[] { result },
Expression.Assign(result, Expression.Convert(Expression.Constant(DateTime.Now.AddSeconds(-1)), typeof(object))),
Expression.Return(blockReturnLabel, result),
Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object))));
LambdaExpression lax = Expression.Lambda<Func<XmlNode, object>>(block, instanceExpression);
Later in the code, we're evaluating <, <=, >, >=, == and != so we want to compare the result of this LambdaExpression to another Expression
Usually, we can assume the LambdaExpression is on the left of the Expression.LessThan
on the right, could be pretty much any expression, but lets assume it's typed.
That means that it could be ConstantExpression or similar... but it has a type.
This means that Expression.LessThan [for example] fails because the LambdaExpression when Expression.Invoke is called on it returns an object and the RHS is whatever that type is.
Assuming that the type boxed inside the object returned from the LambdaExpression is actually comparable to the type on the right hand side; e.g.
(object)5 < 6
How do I write an expression that can compare the boxed type to the unboxed type without crashing?
I've tried various permutations in linqpad, including trying to write this in normal c#- i.e. no Expressions, just nested if-then-else however I couldn't get that working quite right.
Normally, i'd probably write something like this:
/*
int i = 3;
object o = (object)i;
int compare = 4;
*/
DateTime dt = DateTime.Now;
object o = (object)dt;
DateTime compare = DateTime.Now.AddSeconds(1);
bool b = false;
if(o.GetType().IsAssignableFrom(compare.GetType()))
{
if(o is int)
{
b = (int)o < (int)(object)compare;
}
if(o is DateTime)
{
b = (DateTime)o < (DateTime)(object)compare;
}
if(o is decimal)
{
b = (decimal)o < (decimal)(object)compare;
}
}
Console.WriteLine(b);
With this, assuming o and compare are actually the same type and one of them is boxed as an object, we can still perform the < operation...
So I guess my question is, how do I write the above code when I have a LambdaExpression on the left, and Expression on the right [if the two are not the same type, false as a result is better than a crash]
Hope someone can help,
Gareth
How do I write an expression that can
compare the boxed type to the unboxed
type without crashing?
You can use the Expression.Unbox method for this: "Creates a UnaryExpression that represents an explicit unboxing."
Let's take your (int)(object)5 < 6 example:
// boxed int
var left = Expression.Constant(5, typeof(object));
// int
var right = Expression.Constant(6, typeof(int));
// More generally, you can use right.Type instead of typeof(int)
// if its static type is appropriate.
// Otherwise, you may need to unbox it too.
var unboxedLeft = Expression.Unbox(left, typeof(int));
var lessThanEx = Expression.LessThan(unboxedLeft, right);
var expression = Expression.Lambda<Func<bool>>(lessThanEx, null);
// True : (int)(object)5 < 6
bool b = expression.Compile()();
So I guess my question is, how do I
write the above code when I have a
LambdaExpression on the left, and
Expression on the right. [if the two are not the same type, false as a result is better > than a crash]
In this case, you can write a conditional-expression that checks if the run-time type of the boxed-object is the same as the type of the right-hand side, and do the unboxing + less-than comparison if they are, or just return false otherwise.
E.g.
// From earlier
var left = ...
var right = ...
var lessThanEx = ...
var body = Expression.Condition(Expression.TypeEqual(left, right.Type),
lessThanEx,
Expression.Constant(false));
var expression = Expression.Lambda<Func<bool>>(body, null);
Combining my original post with your guys answers- this seems to function in LinqPad
XmlNode node = null;
ParameterExpression instanceExpression = Expression.Parameter(typeof(XmlNode), "instance");
ParameterExpression result = Expression.Parameter(typeof(object), "result");
LabelTarget blockReturnLabel = Expression.Label(typeof(object));
BlockExpression block = Expression.Block(
typeof(object),
new[] { result },
//this would normally be a function invoke
Expression.Assign(result, Expression.Convert(Expression.Constant(DateTime.Now.AddSeconds(-1)), typeof(object))),
Expression.Return(blockReturnLabel, result),
Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object))));
LambdaExpression lax = Expression.Lambda<Func<XmlNode, object>>(block, instanceExpression);
var left = Expression.Invoke(lax, instanceExpression);
//false result
//var right = Expression.Constant(5, typeof(int));
//true result
var right = Expression.Constant(DateTime.Now, typeof(DateTime));
var unboxedLeft = Expression.Unbox(left, right.Type);
var lessThanEx = Expression.LessThan(unboxedLeft, right);
var body = Expression.Condition(Expression.TypeEqual(left, right.Type), lessThanEx, Expression.Constant(false));
var expression = Expression.Lambda<Func<XmlNode, bool>>(body, instanceExpression);
bool b = expression.Compile()(node);
Console.WriteLine(b);

Get value of c# dynamic property via string

I'd like to access the value of a dynamic c# property with a string:
dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };
How can I get the value of d.value2 ("random") if I only have "value2" as a string? In javascript, I could do d["value2"] to access the value ("random"), but I'm not sure how to do this with c# and reflection. The closest I've come is this:
d.GetType().GetProperty("value2") ... but I don't know how to get the actual value from that.
As always, thanks for your help!
Once you have your PropertyInfo (from GetProperty), you need to call GetValue and pass in the instance that you want to get the value from. In your case:
d.GetType().GetProperty("value2").GetValue(d, null);
public static object GetProperty(object target, string name)
{
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
return site.Target(site, target);
}
Add reference to Microsoft.CSharp. Works also for dynamic types and private properties and fields.
Edit: While this approach works, there is almost 20× faster method from the Microsoft.VisualBasic.dll assembly:
public static object GetProperty(object target, string name)
{
return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}
Dynamitey is an open source .net std library, that let's you call it like the dynamic keyword, but using the a string for the property name rather than the compiler doing it for you, and it ends up being equal to reflection speedwise (which is not nearly as fast as using the dynamic keyword, but this is due to the extra overhead of caching dynamically, where the compiler caches statically).
Dynamic.InvokeGet(d,"value2");
The easiest method for obtaining both a setter and a getter for a property which works for any type including dynamic and ExpandoObject is to use FastMember which also happens to be the fastest method around (it uses Emit).
You can either get a TypeAccessor based on a given type or an ObjectAccessor based of an instance of a given type.
Example:
var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");
var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");
dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");
var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");
typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");
typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");
Much of the time when you ask for a dynamic object, you get an ExpandoObject (not in the question's anonymous-but-statically-typed example above, but you mention JavaScript and my chosen JSON parser JsonFx, for one, generates ExpandoObjects).
If your dynamic is in fact an ExpandoObject, you can avoid reflection by casting it to IDictionary, as described at http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.
Once you've cast to IDictionary, you have access to useful methods like .Item and .ContainsKey
The GetProperty/GetValue does not work for Json data, it always generate a null exception, however, you may try this approach:
Serialize your object using JsonConvert:
var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));
Then access it directly casting it back to string:
var pn = (string)z["DynamicFieldName"];
It may work straight applying the Convert.ToString(request)["DynamicFieldName"], however I haven't tested.
d.GetType().GetProperty("value2")
returns a PropertyInfo object.
So then do
propertyInfo.GetValue(d)
To get properties from dynamic doc
when .GetType() returns null, try this:
var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;
This is the way i ve got the value of a property value of a dinamic:
public dynamic Post(dynamic value)
{
try
{
if (value != null)
{
var valorCampos = "";
foreach (Newtonsoft.Json.Linq.JProperty item in value)
{
if (item.Name == "valorCampo")//property name
valorCampos = item.Value.ToString();
}
}
}
catch (Exception ex)
{
}
}
Some of the solutions were not working with a valuekind object that I obtained from a json string, maybe because I did not have a concrete type in my code that was similar to the object that I would obtain from the json string, so how I went about it was
JsonElement myObject = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(jsonStringRepresentationOfMyObject);
/*In this case I know that there is a property with
the name Code, otherwise use TryGetProperty. This will
still return a JsonElement*/
JsonElement propertyCode = myObject.GetProperty("Code");
/*Now with the JsonElement that represents the property,
you can use several methods to retrieve the actual value,
in this case I know that the value in the property is a string,
so I use the GetString method on the object. If I knew the value
was a double, then I would use the GetDouble() method on the object*/
string code = propertyCode.GetString();
That worked for me
In .Net core 3.1 you can try like this
d?.value2 , d?.value3
Similar to the accepted answer, you can also try GetField instead of GetProperty.
d.GetType().GetField("value2").GetValue(d);
Depending on how the actual Type was implemented, this may work when GetProperty() doesn't and can even be faster.
In case you have a dynamic variable such as a DapperRow for example you can first build up an ExpandoObject, then cast the Expando into an IDictionary<string, object>. From then on, getting a value via the name of a property is possible.
Helper method ToExpandoObject:
public static ExpandoObject ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
if (dapperRowProperties == null)
{
return expando as ExpandoObject;
}
foreach (KeyValuePair<string, object> property in dapperRowProperties)
{
if (!expando.ContainsKey(property.Key))
{
expando.Add(property.Key, property.Value);
}
else
{
//prefix the colliding key with a random guid suffixed
expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
}
}
return expando as ExpandoObject;
}
Sample usage, I have marked in bold the casting which gives us access in the example, I have marked the important bits with the ** letters:
using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
foreach (var dynamicParametersForItem in dynamicParametersForItems)
{
var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
if (idsAfterInsertion != null && idsAfterInsertion.Any())
{
**var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
string firstColumnKey = columnKeys.Select(c => c.Key).First();
**object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
}
}
}
In my example, I look up a property value inside a dynamic object DapperRow and first convert the Dapper row into an ExpandoObject and cast it into a dictionary property bag as shown and mentioned in other answers here.
My sample code is the InsertMany method for Dapper extension I am working on, I wanted to grab hold of the multiple ids here after the batch insert.
Use dynamic with Newtonsoft.Json.JsonConvert.DeserializeObject:
// Get JSON string of object
var obj = new { value1 = "some", value2 = "random", value3 = "value" };
var jsonString = JsonConvert.SerializeObject(obj);
// Use dynamic with JsonConvert.DeserializeObject
dynamic d = JsonConvert.DeserializeObject(jsonString);
// output = "some"
Console.WriteLine(d["value1"]);
Sample:
https://dotnetfiddle.net/XGBLU1

Categories

Resources