dynamic keyword enables "maybe" monad? - c#

So I have this in my C# lib:
public static TOut IfNotNull<TIn, TOut>
(this TIn instance, Func<TIn, TOut> func)
{
return instance == null ? default(TOut) : func(instance);
}
Used like:
DateTime? expiration = promo.IfNotNull(p => p.TermsAndConditions.Expiration)
.IfNotNull(e => e.Date);
I keep wracking my brain trying to figure out how to use the C# 4 dynamic keyword to enable this syntax instead:
DateTime? expiration = promoOffer.TermsAndConditions.Maybe()
.Expiration.Maybe()
.Date;
I had a couple examples that I thought worked but they broke down when you start chaining the Maybe()s.
Any ideas?
(Am I wasting my time? Is Maybe() a win over IfNotNull())?

I don't think that using dynamic type is a good idea here, because the syntax isn't going to look much better and you sacrifice the type safety (and IntelliSense) by using dynamic typing.
However, here is an example of what you can do. The idea is that you wrap objects into DynamicWrapper (your monadic value :-)) that can either contain a null value or an actual value. It would inherit from DynamicObject and delegate all calls to the actual object (if there is any) or immediately return null (that would be monadic bind):
class DynamicWrapper : DynamicObject {
public object Object { get; private set; }
public DynamicWrapper(object o) { Object = o; }
public override bool TryGetMember(GetMemberBinder binder, out object result) {
// Special case to be used at the end to get the actual value
if (binder.Name == "Value") result = Object;
// Binding on 'null' value - return 'null'
else if (Object == null) result = new DynamicWrapper(null);
else {
// Binding on some value - delegate to the underlying object
var getMeth = Object.GetType().GetProperty(binder.Name).GetGetMethod();
result = new DynamicWrapper(getMeth.Invoke(Object, new object[0]));
return true;
}
public static dynamic Wrap(object o) {
return new DynamicWrapper(o);
}
}
The example supports only properties and it uses reflection in a pretty inefficient way (I think it could be optimized using DLR). Here is an example how it works:
class Product {
public Product Another { get; set; }
public string Name { get; set; }
}
var p1 = new Product { Another = null };
var p2 = new Product { Another = new Product { Name = "Foo" } };
var p3 = (Product)null;
// prints '' for p1 and p3 (null value) and 'Foo' for p2 (actual value)
string name = DynamicWrapper.Wrap(p1).Another.Name.Value;
Console.WriteLine(name);
Note that you can chain the calls freely - there is only something special at the beginning (Wrap) and at the end (Value), but in the middle, you can write .Another.Another.Another... as many times you want.

This solution is similar to Tomas' except that it uses CallSite to invoke properties on the target instance and also supports casting and extra calls to Maybe (as per your example).
public static dynamic Maybe(this object target)
{
return new MaybeObject(target);
}
private class MaybeObject : DynamicObject
{
private readonly object _target;
public MaybeObject(object target)
{
_target = target;
}
public override bool TryGetMember(GetMemberBinder binder,
out object result)
{
result = _target != null ? Execute<object>(binder).Maybe() : this;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args, out object result)
{
if (binder.Name == "Maybe" &&
binder.ReturnType == typeof (object) &&
binder.CallInfo.ArgumentCount == 0)
{
// skip extra calls to Maybe
result = this;
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (_target != null)
{
// call Execute with an appropriate return type
result = GetType()
.GetMethod("Execute", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(binder.ReturnType)
.Invoke(this, new object[] {binder});
}
else
{
result = null;
}
return true;
}
private object Execute<T>(CallSiteBinder binder)
{
var site = CallSite<Func<CallSite, object, T>>.Create(binder);
return site.Target(site, _target);
}
}
The following code should demonstrate it in use:
var promoOffer = new PromoOffer();
var expDate = promoOffer.TermsAndConditions.Maybe().Expiration.Maybe().Date;
Debug.Assert((DateTime?) expDate == null);
promoOffer.TermsAndConditions = new TermsAndConditions();
expDate = promoOffer.TermsAndConditions.Maybe().Expiration.Maybe().Date;
Debug.Assert((DateTime?) expDate == null);
promoOffer.TermsAndConditions.Expiration = new Expiration();
expDate = promoOffer.TermsAndConditions.Maybe().Expiration.Maybe().Date;
Debug.Assert((DateTime?) expDate == null);
promoOffer.TermsAndConditions.Expiration.Date = DateTime.Now;
expDate = promoOffer.TermsAndConditions.Maybe().Expiration.Maybe().Date;
Debug.Assert((DateTime?) expDate != null);

Related

Enum get value by reference c# [duplicate]

I am trying implement the Data transformation using Reflection1 example in my code.
The GetSourceValue function has a switch comparing various types, but I want to remove these types and properties and have GetSourceValue get the value of the property using only a single string as the parameter. I want to pass a class and property in the string and resolve the value of the property.
Is this possible?
1 Web Archive version of original blog post
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Of course, you will want to add validation and whatnot, but that is the gist of it.
How about something like this:
public static Object GetPropValue(this Object obj, String name) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
public static T GetPropValue<T>(this Object obj, String name) {
Object retval = GetPropValue(obj, name);
if (retval == null) { return default(T); }
// throws InvalidCastException if types are incompatible
return (T) retval;
}
This will allow you to descend into properties using a single string, like this:
DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");
You can either use these methods as static methods or extensions.
Add to any Class:
public class Foo
{
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
public string Bar { get; set; }
}
Then, you can use as:
Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];
What about using the CallByName of the Microsoft.VisualBasic namespace (Microsoft.VisualBasic.dll)? It uses reflection to get properties, fields, and methods of normal objects, COM objects, and even dynamic objects.
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
and then
Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
Great answer by jheddings. I would like to improve it by allowing referencing of aggregated arrays or collections of objects, so that propertyName could be property1.property2[X].property3:
public static object GetPropertyValue(object srcobj, string propertyName)
{
if (srcobj == null)
return null;
object obj = srcobj;
// Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
string[] propertyNameParts = propertyName.Split('.');
foreach (string propertyNamePart in propertyNameParts)
{
if (obj == null) return null;
// propertyNamePart could contain reference to specific
// element (by index) inside a collection
if (!propertyNamePart.Contains("["))
{
PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
if (pi == null) return null;
obj = pi.GetValue(obj, null);
}
else
{ // propertyNamePart is areference to specific element
// (by index) inside a collection
// like AggregatedCollection[123]
// get collection name and element index
int indexStart = propertyNamePart.IndexOf("[")+1;
string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
// get collection object
PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
if (pi == null) return null;
object unknownCollection = pi.GetValue(obj, null);
// try to process the collection as array
if (unknownCollection.GetType().IsArray)
{
object[] collectionAsArray = unknownCollection as object[];
obj = collectionAsArray[collectionElementIndex];
}
else
{
// try to process the collection as IList
System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
if (collectionAsList != null)
{
obj = collectionAsList[collectionElementIndex];
}
else
{
// ??? Unsupported collection type
}
}
}
}
return obj;
}
If I use the code from Ed S. I get
'ReflectionExtensions.GetProperty(Type, string)' is inaccessible due to its protection level
It seems that GetProperty() is not available in Xamarin.Forms. TargetFrameworkProfile is Profile7 in my Portable Class Library (.NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Android, Xamarin.iOS, Xamarin.iOS Classic).
Now I found a working solution:
using System.Linq;
using System.Reflection;
public static object GetPropValue(object source, string propertyName)
{
var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
return property?.GetValue(source);
}
Source
About the nested properties discussion, you can avoid all the reflection stuff if you use the DataBinder.Eval Method (Object, String) as below:
var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");
Of course, you'll need to add a reference to the System.Web assembly, but this probably isn't a big deal.
The method to call has changed in .NET Standard (as of 1.6). Also we can use C# 6's null conditional operator.
using System.Reflection;
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}
The below method works perfect for me:
class MyClass {
public string prop1 { set; get; }
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
}
To get the property value:
MyClass t1 = new MyClass();
...
string value = t1["prop1"].ToString();
To set the property value:
t1["prop1"] = value;
public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
{
var result = new List<KeyValuePair<string, string>>();
if (item != null)
{
var type = item.GetType();
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var pi in properties)
{
var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
if (selfValue != null)
{
result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
}
else
{
result.Add(new KeyValuePair<string, string>(pi.Name, null));
}
}
}
return result;
}
This is a way to get all properties with their values in a List.
Using PropertyInfo of the System.Reflection namespace. Reflection compiles just fine no matter what property we try to access. The error will come up during run-time.
public static object GetObjProperty(object obj, string property)
{
Type t = obj.GetType();
PropertyInfo p = t.GetProperty("Location");
Point location = (Point)p.GetValue(obj, null);
return location;
}
It works fine to get the Location property of an object
Label1.Text = GetObjProperty(button1, "Location").ToString();
We'll get the Location : {X=71,Y=27}
We can also return location.X or location.Y on the same way.
public class YourClass
{
//Add below line in your class
public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
public string SampleProperty { get; set; }
}
//And you can get value of any property like this.
var value = YourClass["SampleProperty"];
The following code is a Recursive method for displaying the entire hierarchy of all of the Property Names and Values contained in an object's instance. This method uses a simplified version of AlexD's GetPropertyValue() answer above in this thread. Thanks to this discussion thread, I was able to figure out how to do this!
For example, I use this method to show an explosion or dump of all of the properties in a WebService response by calling the method as follows:
PropertyValues_byRecursion("Response", response, false);
public static object GetPropertyValue(object srcObj, string propertyName)
{
if (srcObj == null)
{
return null;
}
PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
if (pi == null)
{
return null;
}
return pi.GetValue(srcObj);
}
public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
/// Processes all of the objects contained in the parent object.
/// If an object has a Property Value, then the value is written to the Console
/// Else if the object is a container, then this method is called recursively
/// using the current path and current object as parameters
// Note: If you do not want to see null values, set showNullValues = false
foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
{
// Build the current object property's namespace path.
// Recursion extends this to be the property's full namespace path.
string currentPath = parentPath + "." + pi.Name;
// Get the selected property's value as an object
object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
if (myPropertyValue == null)
{
// Instance of Property does not exist
if (showNullValues)
{
Console.WriteLine(currentPath + " = null");
// Note: If you are replacing these Console.Write... methods callback methods,
// consider passing DBNull.Value instead of null in any method object parameters.
}
}
else if (myPropertyValue.GetType().IsArray)
{
// myPropertyValue is an object instance of an Array of business objects.
// Initialize an array index variable so we can show NamespacePath[idx] in the results.
int idx = 0;
foreach (object business in (Array)myPropertyValue)
{
if (business == null)
{
// Instance of Property does not exist
// Not sure if this is possible in this context.
if (showNullValues)
{
Console.WriteLine(currentPath + "[" + idx.ToString() + "]" + " = null");
}
}
else if (business.GetType().IsArray)
{
// myPropertyValue[idx] is another Array!
// Let recursion process it.
PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
}
else if (business.GetType().IsSealed)
{
// Display the Full Property Path and its Value
Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
}
else
{
// Unsealed Type Properties can contain child objects.
// Recurse into my property value object to process its properties and child objects.
PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
}
idx++;
}
}
else if (myPropertyValue.GetType().IsSealed)
{
// myPropertyValue is a simple value
Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
}
else
{
// Unsealed Type Properties can contain child objects.
// Recurse into my property value object to process its properties and child objects.
PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
}
}
}
public static TValue GetFieldValue<TValue>(this object instance, string name)
{
var type = instance.GetType();
var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType) && e.Name == name);
return (TValue)field?.GetValue(instance);
}
public static TValue GetPropertyValue<TValue>(this object instance, string name)
{
var type = instance.GetType();
var field = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.PropertyType) && e.Name == name);
return (TValue)field?.GetValue(instance);
}
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)
Here is another way to find a nested property that doesn't require the string to tell you the nesting path. Credit to Ed S. for the single property method.
public static T FindNestedPropertyValue<T, N>(N model, string propName) {
T retVal = default(T);
bool found = false;
PropertyInfo[] properties = typeof(N).GetProperties();
foreach (PropertyInfo property in properties) {
var currentProperty = property.GetValue(model, null);
if (!found) {
try {
retVal = GetPropValue<T>(currentProperty, propName);
found = true;
} catch { }
}
}
if (!found) {
throw new Exception("Unable to find property: " + propName);
}
return retVal;
}
public static T GetPropValue<T>(object srcObject, string propName) {
return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null);
}
You never mention what object you are inspecting, and since you are rejecting ones that reference a given object, I will assume you mean a static one.
using System.Reflection;
public object GetPropValue(string prop)
{
int splitPoint = prop.LastIndexOf('.');
Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
object obj = null;
return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}
Note that I marked the object that is being inspected with the local variable obj. null means static, otherwise set it to what you want. Also note that the GetEntryAssembly() is one of a few available methods to get the "running" assembly, you may want to play around with it if you are having a hard time loading the type.
Have a look at the Heleonix.Reflection library. You can get/set/invoke members by paths, or create a getter/setter (lambda compiled into a delegate) which is faster than reflection. For example:
var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);
Or create a getter once and cache for reuse (this is more performant but might throw NullReferenceException if an intermediate member is null):
var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
Or if you want to create a List<Action<object, object>> of different getters, just specify base types for compiled delegates (type conversions will be added into compiled lambdas):
var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
Although the original question was about how to get the value of the property using only a single string as the parameter, it makes a lot of sense here to use an Expression rather than simply a string to ensure that the caller never uses a hard coded property name. Here is a one line version with usage:
public static class Utils
...
public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
=> (TVal)((x.Body as MemberExpression)?.Member as PropertyInfo)!.GetValue(t);
...
var val = Utils.GetPropertyValue(foo, p => p.Bar);
Here is a slightly better version in terms of readability a error handling:
public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
{
var m = (x.Body as MemberExpression)?.Member;
var p = m as PropertyInfo;
if (null == p)
throw new ArgumentException($"Unknown property: {typeof(T).Name}.{(m?.Name??"???")}");
return (TVal)p.GetValue(t);
}
In short you pass in a lambda expression reading a property. The body of the lambda - the part on the right of the fat arrow - is a member expression from which you can get the member name and which you can cast to a PropertyInfo, provided the member is actually a Property and not, for instance, a method.
In the short version, the null forgiving operator - the ! in the expression - tells the compiler that the PropertyInfo will not be null. This is a big lie and you will get a NullReferenceException at runtime. The longer version gives you the name of the property if it manages to get it.
PS: Thanks to Oleg G. for the initial version of this code :)
shorter way ....
var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };
var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());
jheddings and AlexD both wrote excellent answers on how to resolve property strings. I'd like to throw mine in the mix, since I wrote a dedicated library exactly for that purpose.
Pather.CSharp's main class is Resolver. Per default it can resolve properties, array and dictionary entries.
So, for example, if you have an object like this
var o = new { Property1 = new { Property2 = "value" } };
and want to get Property2, you can do it like this:
IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path);
//=> "value"
This is the most basic example of the paths it can resolve. If you want to see what else it can, or how you can extend it, just head to its Github page.
Here's what I got based on other answers. A little overkill on getting so specific with the error handling.
public static T GetPropertyValue<T>(object sourceInstance, string targetPropertyName, bool throwExceptionIfNotExists = false)
{
string errorMsg = null;
try
{
if (sourceInstance == null || string.IsNullOrWhiteSpace(targetPropertyName))
{
errorMsg = $"Source object is null or property name is null or whitespace. '{targetPropertyName}'";
Log.Warn(errorMsg);
if (throwExceptionIfNotExists)
throw new ArgumentException(errorMsg);
else
return default(T);
}
Type returnType = typeof(T);
Type sourceType = sourceInstance.GetType();
PropertyInfo propertyInfo = sourceType.GetProperty(targetPropertyName, returnType);
if (propertyInfo == null)
{
errorMsg = $"Property name '{targetPropertyName}' of type '{returnType}' not found for source object of type '{sourceType}'";
Log.Warn(errorMsg);
if (throwExceptionIfNotExists)
throw new ArgumentException(errorMsg);
else
return default(T);
}
return (T)propertyInfo.GetValue(sourceInstance, null);
}
catch(Exception ex)
{
errorMsg = $"Problem getting property name '{targetPropertyName}' from source instance.";
Log.Error(errorMsg, ex);
if (throwExceptionIfNotExists)
throw;
}
return default(T);
}
Here is my solution. It works also with COM objects and allows to access collection/array items from COM objects.
public static object GetPropValue(this object obj, string name)
{
foreach (string part in name.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
if (type.Name == "__ComObject")
{
if (part.Contains('['))
{
string partWithoundIndex = part;
int index = ParseIndexFromPropertyName(ref partWithoundIndex);
obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
}
else
{
obj = Versioned.CallByName(obj, part, CallType.Get);
}
}
else
{
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
}
return obj;
}
private static int ParseIndexFromPropertyName(ref string name)
{
int index = -1;
int s = name.IndexOf('[') + 1;
int e = name.IndexOf(']');
if (e < s)
{
throw new ArgumentException();
}
string tmp = name.Substring(s, e - s);
index = Convert.ToInt32(tmp);
name = name.Substring(0, s - 1);
return index;
}
Whenever you want to loop over all properties in on an object and then use each value of the property must use this piece of code:
foreach (var property in request.GetType().GetProperties())
{
var valueOfProperty = property.GetValue(properties, null);
}

Is there a way to perform a chained null check in a dynamic/expando?

C# has the usefull Null Conditional Operator. Well explained in this answer too.
I was wondering if it is possible to do a similar check like this when my object is a dynamic/expando object. Let me show you some code:
Given this class hierarchy
public class ClsLevel1
{
public ClsLevel2 ClsLevel2 { get; set; }
public ClsLevel1()
{
this.ClsLevel2 = new ClsLevel2(); // You can comment this line to test
}
}
public class ClsLevel2
{
public ClsLevel3 ClsLevel3 { get; set; }
public ClsLevel2()
{
this.ClsLevel3 = new ClsLevel3();
}
}
public class ClsLevel3
{
// No child
public ClsLevel3()
{
}
}
If i perform this kind of chained null check, it works
ClsLevel1 levelRoot = new ClsLevel1();
if (levelRoot?.ClsLevel2?.ClsLevel3 != null)
{
// will enter here if you DO NOT comment the content of the ClsLevel1 constructor
}
else
{
// will enter here if you COMMENT the content of the ClsLevel1
}
Now, i will try to reproduce this behaviour with dynamics (ExpandoObjects)
dynamic dinRoot = new ExpandoObject();
dynamic DinLevel1 = new ExpandoObject();
dynamic DinLevel2 = new ExpandoObject();
dynamic DinLevel3 = new ExpandoObject();
dinRoot.DinLevel1 = DinLevel1;
dinRoot.DinLevel1.DinLevel2 = DinLevel2;
//dinRoot.DinLevel1.DinLevel2.DinLevel3 = DinLevel3; // You can comment this line to test
if (dinRoot?.DinLevel1?.DinLevel2?.DinLevel3 != null)
{
// Obviously it will raise an exception because the DinLevel3 does not exists, it is commented right now.
}
Is there a way to simulate this behaviour with dynamics? I mean, check for a null in a long chain of members?
If you want to support this in a more natural way you can inherit from DynamicObject and provide a custom implementation:
class MyExpando : DynamicObject
{
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name.ToLower();
result = _dictionary.ContainsKey(name) ? _dictionary[name] : null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name.ToLower()] = value;
return true;
}
}
Testing:
private static void Main(string[] args)
{
dynamic foo = new MyExpando();
if (foo.Boo?.Lol ?? true)
{
Console.WriteLine("It works!");
}
Console.ReadLine();
}
The output will be "It works!". Since Boo does not exist we get a null reference so that the Null Conditional Operator can work.
What we do here is to return a null reference to the output parameter of TryGetMember every time a property is not found and we always return true.
EDIT: fixed, as ExpandoObjects and extension methods do not work well together. Slightly less nice, but hopefully still usable.
Helper method(s):
public static class DynamicExtensions
{
public static Object TryGetProperty(ExpandoObject obj, String name)
{
return name.Split('.')
.Aggregate((Object)obj, (o, s) => o != null
? TryGetPropertyInternal(o, s)
: null);
}
private static Object TryGetPropertyInternal(Object obj, String name)
{
var dict = obj as IDictionary<String, Object>;
return (dict?.ContainsKey(name) ?? false) ? dict[name] : null;
}
}
Usage:
if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)

Why Json.NET can't deserialize structs without JsonConstructor attribute? [duplicate]

I have a class that has a default constructor and also an overloaded constructor that takes in a set of parameters. These parameters match to fields on the object and are assigned on construction. At this point i need the default constructor for other purposes so i would like to keep it if i can.
My Problem: If I remove the default constructor and pass in the JSON string, the object deserializes correctly and passes in the constructor parameters without any issues. I end up getting back the object populated the way I would expect. However, as soon as I add the default constructor into the object, when i call JsonConvert.DeserializeObject<Result>(jsontext) the properties are no longer populated.
At this point I have tried adding new JsonSerializerSettings(){CheckAdditionalContent = true} to the deserialization call. That did not do anything.
Another note: the constructor parameters do match the names of the fields exactly except that the parameters are start with a lowercase letter. I wouldn't think this would matter since, like i mentioned, the deserialization works fine with no default constructor.
Here is a sample of my constructors:
public Result() { }
public Result(int? code, string format, Dictionary<string, string> details = null)
{
Code = code ?? ERROR_CODE;
Format = format;
if (details == null)
Details = new Dictionary<string, string>();
else
Details = details;
}
Json.Net prefers to use the default (parameterless) constructor on an object if there is one. If there are multiple constructors and you want Json.Net to use a non-default one, then you can add the [JsonConstructor] attribute to the constructor that you want Json.Net to call.
[JsonConstructor]
public Result(int? code, string format, Dictionary<string, string> details = null)
{
...
}
It is important that the constructor parameter names match the corresponding property names of the JSON object (ignoring case) for this to work correctly. You do not necessarily have to have a constructor parameter for every property of the object, however. For those JSON object properties that are not covered by the constructor parameters, Json.Net will try to use the public property accessors (or properties/fields marked with [JsonProperty]) to populate the object after constructing it.
If you do not want to add attributes to your class or don't otherwise control the source code for the class you are trying to deserialize, then another alternative is to create a custom JsonConverter to instantiate and populate your object. For example:
class ResultConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Result));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load the JSON for the Result into a JObject
JObject jo = JObject.Load(reader);
// Read the properties which will be used as constructor parameters
int? code = (int?)jo["Code"];
string format = (string)jo["Format"];
// Construct the Result object using the non-default constructor
Result result = new Result(code, format);
// (If anything else needs to be populated on the result object, do that here)
// Return the result
return result;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Then, add the converter to your serializer settings, and use the settings when you deserialize:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new ResultConverter());
Result result = JsonConvert.DeserializeObject<Result>(jsontext, settings);
A bit late and not exactly suited here, but I'm gonna add my solution here, because my question had been closed as a duplicate of this one, and because this solution is completely different.
I needed a general way to instruct Json.NET to prefer the most specific constructor for a user defined struct type, so I can omit the JsonConstructor attributes which would add a dependency to the project where each such struct is defined.
I've reverse engineered a bit and implemented a custom contract resolver where I've overridden the CreateObjectContract method to add my custom creation logic.
public class CustomContractResolver : DefaultContractResolver {
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var c = base.CreateObjectContract(objectType);
if (!IsCustomStruct(objectType)) return c;
IList<ConstructorInfo> list = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e => e.GetParameters().Length).ToList();
var mostSpecific = list.LastOrDefault();
if (mostSpecific != null)
{
c.OverrideCreator = CreateParameterizedConstructor(mostSpecific);
c.CreatorParameters.AddRange(CreateConstructorParameters(mostSpecific, c.Properties));
}
return c;
}
protected virtual bool IsCustomStruct(Type objectType)
{
return objectType.IsValueType && !objectType.IsPrimitive && !objectType.IsEnum && !objectType.Namespace.IsNullOrEmpty() && !objectType.Namespace.StartsWith("System.");
}
private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
method.ThrowIfNull("method");
var c = method as ConstructorInfo;
if (c != null)
return a => c.Invoke(a);
return a => method.Invoke(null, a);
}
}
I'm using it like this.
public struct Test {
public readonly int A;
public readonly string B;
public Test(int a, string b) {
A = a;
B = b;
}
}
var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings {
ContractResolver = new CustomContractResolver()
});
var t = JsonConvert.DeserializeObject<Test>(json);
t.A.ShouldEqual(1);
t.B.ShouldEqual("Test");
Based on some of the answers here, I have written a CustomConstructorResolver for use in a current project, and I thought it might help somebody else.
It supports the following resolution mechanisms, all configurable:
Select a single private constructor so you can define one private constructor without having to mark it with an attribute.
Select the most specific private constructor so you can have multiple overloads, still without having to use attributes.
Select the constructor marked with an attribute of a specific name - like the default resolver, but without a dependency on the Json.Net package because you need to reference Newtonsoft.Json.JsonConstructorAttribute.
public class CustomConstructorResolver : DefaultContractResolver
{
public string ConstructorAttributeName { get; set; } = "JsonConstructorAttribute";
public bool IgnoreAttributeConstructor { get; set; } = false;
public bool IgnoreSinglePrivateConstructor { get; set; } = false;
public bool IgnoreMostSpecificConstructor { get; set; } = false;
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
// Use default contract for non-object types.
if (objectType.IsPrimitive || objectType.IsEnum) return contract;
// Look for constructor with attribute first, then single private, then most specific.
var overrideConstructor =
(this.IgnoreAttributeConstructor ? null : GetAttributeConstructor(objectType))
?? (this.IgnoreSinglePrivateConstructor ? null : GetSinglePrivateConstructor(objectType))
?? (this.IgnoreMostSpecificConstructor ? null : GetMostSpecificConstructor(objectType));
// Set override constructor if found, otherwise use default contract.
if (overrideConstructor != null)
{
SetOverrideCreator(contract, overrideConstructor);
}
return contract;
}
private void SetOverrideCreator(JsonObjectContract contract, ConstructorInfo attributeConstructor)
{
contract.OverrideCreator = CreateParameterizedConstructor(attributeConstructor);
contract.CreatorParameters.Clear();
foreach (var constructorParameter in base.CreateConstructorParameters(attributeConstructor, contract.Properties))
{
contract.CreatorParameters.Add(constructorParameter);
}
}
private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
var c = method as ConstructorInfo;
if (c != null)
return a => c.Invoke(a);
return a => method.Invoke(null, a);
}
protected virtual ConstructorInfo GetAttributeConstructor(Type objectType)
{
var constructors = objectType
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(c => c.GetCustomAttributes().Any(a => a.GetType().Name == this.ConstructorAttributeName)).ToList();
if (constructors.Count == 1) return constructors[0];
if (constructors.Count > 1)
throw new JsonException($"Multiple constructors with a {this.ConstructorAttributeName}.");
return null;
}
protected virtual ConstructorInfo GetSinglePrivateConstructor(Type objectType)
{
var constructors = objectType
.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
return constructors.Length == 1 ? constructors[0] : null;
}
protected virtual ConstructorInfo GetMostSpecificConstructor(Type objectType)
{
var constructors = objectType
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.OrderBy(e => e.GetParameters().Length);
var mostSpecific = constructors.LastOrDefault();
return mostSpecific;
}
}
Here is the complete version with XML documentation as a gist:
https://gist.github.com/bjorn-jarisch/80f77f4b6bdce3b434b0f7a1d06baa95
Feedback appreciated.
The default behaviour of Newtonsoft.Json is going to find the public constructors. If your default constructor is only used in containing class or the same assembly, you can reduce the access level to protected or internal so that Newtonsoft.Json will pick your desired public constructor.
Admittedly, this solution is rather very limited to specific cases.
internal Result() { }
public Result(int? code, string format, Dictionary<string, string> details = null)
{
Code = code ?? ERROR_CODE;
Format = format;
if (details == null)
Details = new Dictionary<string, string>();
else
Details = details;
}
Based on the answer by Zoltan, I created a variation that lets you use a specific constructor based on its signature.
Usage
return new JsonSerializerSettings
{
ContractResolver = new DynamicObjectResolver(t =>
{
if (t == typeof(QueueProperties))
return new Type[] { typeof(string) };
return null;
})
};
An here is the implementation
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Concurrent;
using System.Reflection;
namespace ConsoleApp76.Json
{
class DynamicObjectResolver : DefaultContractResolver
{
private readonly Func<Type, Type[]> GetConstructorSignature;
private readonly ConcurrentDictionary<Type, ConstructorInfo> TypeToConstructorLookup =
new ConcurrentDictionary<Type, ConstructorInfo>();
public DynamicObjectResolver(Func<Type, Type[]> getConstructorSignature)
{
if (getConstructorSignature is null)
throw new ArgumentNullException(nameof(getConstructorSignature));
GetConstructorSignature = getConstructorSignature;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var result = base.CreateObjectContract(objectType);
ConstructorInfo constructor = TypeToConstructorLookup.GetOrAdd(objectType, t => FindConstructorInfo(t));
if (constructor is null)
return result;
result.OverrideCreator = CreateParameterizedConstructor(constructor);
foreach (var param in CreateConstructorParameters(constructor, result.Properties))
result.CreatorParameters.Add(param);
return result;
}
private ConstructorInfo FindConstructorInfo(Type objectType)
{
Type[] constructorSignature = GetConstructorSignature(objectType);
if (constructorSignature is null)
return null;
return objectType.GetConstructor(
bindingAttr:
System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance,
binder: null,
types: new Type[] { typeof(string) },
modifiers: null);
}
private static ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
{
if (method is null)
throw new ArgumentNullException(nameof(method));
var c = method as ConstructorInfo;
if (c != null)
return a => c.Invoke(a);
return a => method.Invoke(null, a);
}
}
}
Solution:
public Response Get(string jsonData) {
var json = JsonConvert.DeserializeObject<modelname>(jsonData);
var data = StoredProcedure.procedureName(json.Parameter, json.Parameter, json.Parameter, json.Parameter);
return data;
}
Model:
public class modelname {
public long parameter{ get; set; }
public int parameter{ get; set; }
public int parameter{ get; set; }
public string parameter{ get; set; }
}

Using reflection to set List<dynamic> to List<T>

Say, I have these properties in a class :
public class Example
{
public List<Toyota> listToyota;
public List<Honda> listHonda;
public List<Huyndai> listHuyndai;
...
...
}
And there will be more properties if there are new car brands. Each brand is a table.
Normally, I would do this to get the data from tables :
Example result = new Example();
switch (brandname)
{
case "Toyota":
result.listToyota = * select table from context * ;
break;
case "Honda":
result.listHonda = * select table from context * ;
break;
...
}
Also, I'll have to add more code when there are new brands. I found this very annoying/time-consuming and decided to switch to a dynamic approach. I've sucessfully get the tables dynamically :
tblName = "Toyota";
IEnumerable<dynamic> table = typeof(MyContext).GetProperty(tblName).GetValue(context, null) as IEnumerable<dynamic>;
But I failed to dynamically set the property value, in this example, is listToyota :
query = (from a in table select a).ToList() as List<dynamic>;
SetPropertyValue(result, "listToyota", query);
I got this error :
Object of type 'System.Collections.Generic.List1[System.Object]'
cannot be converted to type
'System.Collections.Generic.List1[Toyota]'.
SetPropertyValue is a very simple function using System.Reflection :
static void SetPropertyValue(object p, string propName, object value)
{
Type t = p.GetType();
System.Reflection.PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
info.SetValue(p, value, null);
}
Any advices are greatly appreciated!
Please try something like this
static void SetPropertyValue(object p, string propName, object value)
{
Type t = p.GetType();
System.Reflection.PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
var elemtype = info.PropertyType.GetElementType();
var castmethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elemtype);
var tolist = typeof(Enumerable).GetMethod("ToList", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elemtype);
var collection = castmethod.Invoke(null, new object[] { value });
var list = tolist.Invoke(null, new object[] { collection });
info.SetValue(p, list, null);
}
I think the main problem is your software design. I wouldn't use dynamic this way.
I would create a Brand-Class. If you want to use dynamic, try something like this:
public class DynamicBrand : DynamicObject
{
private IDictionary<string, object> myDynamicValues;
public DynamicBrand()
: base()
{
myDynamicValues = new Dictionary<string, object>();
}
public void AddMember(string Name, object Value)
{
if (!myDynamicValues.ContainsKey(Name.Trim().ToLower()))
{
myDynamicValues.Add(Name.ToLower().Trim(), Value);
}
else
{
throw new Exception("The Member with the Name: " + Name + " already exists!");
}
}
public override bool TrySetMember(SetMemberBinder Binder, object Value)
{
if (myDynamicValues.ContainsKey(Binder.Name.ToLower()))
{
myDynamicValues[Binder.Name.ToLower()] = Value;
return true;
}
else
{
myDynamicValues.Add(Binder.Name.ToLower(), Value);
}
return true;
}
publc override bool TryGetMember(GetMemberBinder Binder, out object Result)
{
if (myDynamicValues.ContainsKey(Binder.Name.ToLower()))
{
Result = myDynamicValues[Binder.Name.ToLower()];
return true;
}
else
{
Result = null;
return false;
}
}
I would change your example class
public class Example
{
// string = brand-name; list = list of dynamic brand items
public Dictionary<string, List<DynamicBrand>> brands;
}
Whenyou fill your data, just add a new dynamic brand to your brands-list and simply add the member you need.
EDIT: Dynamic isn't a very nice solution for your problem. I would think about a completly different structure.

C# dynamic classes

I'm talking about something similar to dynamic. This didn't answer my question, hence this question. I want to have a class that I can add properties to at runtime. It needs to be inherited from the type object.
I've seen inheriting from DynamicObject, but it didn't state how to add properties at run-time. Could some light be shed on this for me pls?
I have a class like this:
public class SomeModel : DynamicObject {
public string SomeMandatoryProperty {get; set;}
}
I'd like to add all properties from another class to this class at runtime. So eg.
SomeModel m = new SomeModel();
m = someOtherClass;
string hi = m.otherClassProp; //Property from other class is added.
string mandatory = m.SomeMandatoryProperty; //From the mandatory property set previously.
I think you are looking for ExpandoObject:
The ExpandoObject class enables you to
add and delete members of its
instances at run time and also to set
and get values of these members. This
class supports dynamic binding, which
enables you to use standard syntax
like sampleObject.sampleMember instead
of more complex syntax like
sampleObject.GetAttribute("sampleMember").
dynamic manager;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You should be able to make use of ExpandoObject instead. An ExpandoObject can have members added or removed at runtime and has very nice support if you want to convert to XML etc.
From MSDN Documentation:
dynamic employee, manager;
employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You'd want to use the ExpandoObject as you can dynamically add properties as needed. There isn't however a direct way to populate an instance with the values from another object easily. You'll have to add it manually using reflection.
Do you want to write a wrapper object where you could add properties to while still accessing the inner? You may want to consider it that way you don't have to manage two copies of values between two different object instances. I wrote a test class to wrap string objects to demonstrate how you can do this (similar to how the ExpandoObject works). It should give you an idea on how you can do this for your types.
class DynamicString : DynamicObject
{
static readonly Type strType = typeof(string);
private string instance;
private Dictionary<string, object> dynProperties;
public DynamicString(string instance)
{
this.instance = instance;
dynProperties = new Dictionary<string, object>();
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(instance, suffix);
}
public override string ToString()
{
return instance;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type != typeof(string))
return base.TryConvert(binder, out result);
result = instance;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var method = strType.GetMethod(binder.Name, args.Select(a => a.GetType()).ToArray());
if (method == null)
{
result = null;
return false;
}
result = method.Invoke(instance, args);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var members = strType.GetMember(binder.Name);
if (members.Length > 0)
{
var member = members.Single();
switch (member.MemberType)
{
case MemberTypes.Property:
result = ((PropertyInfo)member).GetValue(instance, null);
return true;
break;
case MemberTypes.Field:
result = ((FieldInfo)member).GetValue(instance);
return true;
break;
}
}
return dynProperties.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var ret = base.TrySetMember(binder, value);
if (ret) return true;
dynProperties[binder.Name] = value;
return true;
}
}
If you want to be adventurous, you can define your own meta objects to handle the bindings. You could end up with reusable meta objects for different types and simplify your code immensely. I've been playing with this for a while and have this so far. It doesn't handle dynamically adding properties yet. I won't be working on this any further but I'll just leave it here for reference.
class DynamicString : DynamicObject
{
class DynamicStringMetaObject : DynamicMetaObject
{
public DynamicStringMetaObject(Expression parameter, object value)
: base(parameter, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
if (binder.Type == typeof(string))
{
var valueType = Value.GetType();
return new DynamicMetaObject(
Expression.MakeMemberAccess(
Expression.Convert(Expression, valueType),
valueType.GetProperty("Instance")),
BindingRestrictions.GetTypeRestriction(Expression, valueType));
}
return base.BindConvert(binder);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
System.Diagnostics.Trace.WriteLine(String.Format("BindGetMember: {0}", binder.Name));
var valueType = Value.GetType();
var self = Expression.Convert(Expression, valueType);
var valueMembers = valueType.GetMember(binder.Name);
if (valueMembers.Length > 0)
{
return BindGetMember(self, valueMembers.Single());
}
var members = typeof(string).GetMember(binder.Name);
if (members.Length > 0)
{
var instance =
Expression.MakeMemberAccess(
self,
valueType.GetProperty("Instance"));
return BindGetMember(instance, members.Single());
}
return base.BindGetMember(binder);
}
private DynamicMetaObject BindGetMember(Expression instance, MemberInfo member)
{
return new DynamicMetaObject(
Expression.Convert(
Expression.MakeMemberAccess(instance, member),
typeof(object)),
BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
);
}
}
public string Instance { get; private set; }
public DynamicString(string instance)
{
Instance = instance;
}
public override DynamicMetaObject GetMetaObject(Expression parameter)
{
return new DynamicStringMetaObject(parameter, this);
}
public override string ToString()
{
return Instance;
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, Instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(Instance, suffix);
}
}

Categories

Resources