How do you convert any C# object to an ExpandoObject? [duplicate] - c#

This question already has answers here:
Convert class to dynamic and add properties
(5 answers)
can one convert a dynamic object to an ExpandoObject (c#)
(2 answers)
How to extend an existing object in c# 4.0 using dynamics
(1 answer)
Closed 5 years ago.
I've read a lot about how ExpandoObject can be used to dynamically create objects from scratch by adding properties, but I haven't yet found how you do the same thing starting from a non-dynamic C# object that you already have.
For instance, I have this trivial class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
I would like to convert this to ExpandoObject so that I can add or remove properties based on what it has already, rather than rebuilding the same thing from scratch. Is this possible?
Edit: the questions marked as duplicate are clearly NOT duplicates of this one.

It could be done like this:
var person = new Person { Id = 1, Name = "John Doe" };
var expando = new ExpandoObject();
var dictionary = (IDictionary<string, object>)expando;
foreach (var property in person.GetType().GetProperties())
dictionary.Add(property.Name, property.GetValue(person));

You cannot "convert" a Person class into an expando object. However, you could create a wrapper DynamicObject that contains a Person and forwards all of the fields.
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Reflection;
namespace SandboxConsole
{
public class ExpandoWrapper : DynamicObject
{
private readonly object _item;
private readonly Dictionary<string, PropertyInfo> _lookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCulture);
private readonly Dictionary<string, PropertyInfo> _ignoreCaseLookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, Box> _lookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCulture);
private readonly Dictionary<string, Box> _ignoreCaseLookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCultureIgnoreCase);
private class Box
{
public Box(object item)
{
Item = item;
}
public object Item { get; }
}
public ExpandoWrapper(object item)
{
_item = item;
var itemType = item.GetType();
foreach (var propertyInfo in itemType.GetProperties())
{
_lookup.Add(propertyInfo.Name, propertyInfo);
_ignoreCaseLookup.Add(propertyInfo.Name, propertyInfo);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
result = lookup.GetValue(_item);
return true;
}
Box box;
if (binder.IgnoreCase)
{
_ignoreCaseLookupExtra.TryGetValue(binder.Name, out box);
}
else
{
_lookupExtra.TryGetValue(binder.Name, out box);
}
if (box != null)
{
result = box.Item;
return true;
}
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
lookup.SetValue(_item, value);
return true;
}
var box = new Box(value);
_ignoreCaseLookupExtra[binder.Name] = box;
_lookupExtra[binder.Name] = box;
return true;
}
}
}
Example usage:
using System;
namespace SandboxConsole
{
class Program
{
static void Main(string[] args)
{
var person = new Person() {Id = 1};
dynamic wrapper = new ExpandoWrapper(person);
wrapper.Id = 2;
wrapper.NewField = "Foo";
Console.WriteLine(wrapper.Id);
Console.WriteLine(person.Id);
Console.WriteLine(wrapper.NewField);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
}

Related

Extension method to remove not primitive property of an object

I'd like an extension method to create an object based on another but keep only the primitive properties. This object will be dumped into a log file in JSON format for logging.
Based on the classes shown below, in this sample, the created object should keep only these properties :
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
I am using .NET Framework 4.7
How can I do this?
// To use like this
var order = new Order();
var forLog = order.RemovePrimitives();
// Sample of classes
public class Order
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public List<Item> Items { get; set; }
public Address Address { get; set; }
}
public class Item{}
public class Address{}
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
// I need to create an anonymous, named 'TheNewObjectHere' object but only with primitives
// I will dump the object to push to a log file. I need only primitives
return JsonConvert.SerializeObject(TheNewObjectHere, Formatting.Indented);
}
}
Thanks
try this
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
var jsonObj = JObject.FromObject(obj);
var propToRemove = jsonObj.Properties().Where(i => !i.Value.GetType().ToString()
.Contains("JValue")).ToList();
foreach (var prop in propToRemove) prop.Remove();
return jsonObj.ToString();
}
}
You can use reflection to get primitive properties and then use JObject to build a JSON object dynamically.
public static readonly Type[] AdditionalPrimities = new[] { typeof(decimal), typeof(string) };
public static string RemovePrimitives<T>(this T obj)
{
var jObj = new JObject();
var props = GetPrimitiveProperties(obj);
foreach (var item in props)
{
var value = item.GetValue(obj);
if (value != null)
{
jObj.Add(item.Name, new JValue(value));
}
}
return jObj.ToString(Newtonsoft.Json.Formatting.Indented);
}
public static PropertyInfo[] GetPrimitiveProperties<T>()
{
var properties = typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(r => r.PropertyType.IsPrimitive || (r.PropertyType.IsGenericType && Nullable.GetUnderlyingType(r.PropertyType) != null) || AdditionalPrimities.Contains(r.PropertyType))
.Select(r => r)
.ToArray();
return properties;
}
public static void Main()
{
var order = new Order { FirstName = "abc", LastName = "cde", Address = new Address(), Age2 = 3, Age = 1 };
var final = order.RemovePrimitives();
Console.WriteLine(final);
}
Fiddle

Reflection loop propertes inside a class

I can't find a solution to my problem, so I try ask here. I have a class and I want to have a method in the class to test for the state of the Properties. The method should return true if any of the properties has more one or more values assigned. But i cannot find any examples of how to loop trough all the properties of the class itself with reflection and test if Count is > than 0.
Or should I use another technique than reflection?
I just want to avoid hard coding the Properties one more time in the Test method.
using System.Reflection;
public class cP
{
public Guid gid { get; set; } = Guid.NewGuid();
public List<string> p1 { get; set; } = new List<string>();
public List<string> p2 { get; set; } = new List<string>();
public bool HasDefinedValues()
{
List<PropertyInfo> properties = this.GetType().GetProperties().ToList();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(List<int>))
{
string PName = property.Name;
if (((List<int>)property.GetValue(property.Name, null)).Count > 0) { return true; };
}
}
return false;
}
}
This is working now 😃
using System.Reflection;
public class cP
{
public Guid gid { get; set; } = Guid.NewGuid();
public List<string> p1 { get; set; } = new List<string>();
public List<string> p2 { get; set; } = new List<string>();
public bool HasDefinedValues()
{
List<PropertyInfo> properties = this.GetType().GetProperties().ToList();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(List<string>))
{
if (((List<string>)property.GetValue(this, null)).Count > 0) { return true; };
}
}
return false;
}
}

How do I detect an ExpandoObject vs a Dynamic Object?

How to I determine if a Type is an ExpandoObject vs a Dynamic object?
This is returning true for both:
public static bool IsDynamicObject(Type type)
{
return typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type);
}
Example Code for Dynamic Object:
public class Entity
{
public Guid Id { get; set; }
public String Name { get; set; }
}
Delta<Entity> x = new Delta<Entity>();
dynamic dynamicX = x;
dynamicX.Name = nameof(Entity);
dynamicX.Id = typeof(Entity).GUID;
Example Code for Expando Object:
dynamic childX = new ExpandoObject();
childX.A = 1;
The ExpandoObject can be casted to a dictionary to get the member names and values
public static bool IsExpandoObject(object objectValue)
{
if (objectValue == null)
return false;
if (IsDynamicObject(objectValue.GetType()))
{
IDictionary<string, object> expandoPropertyValues = objectValue as IDictionary<string, object>;
return expandoPropertyValues != null;
}
return false;
}
public static bool IsDynamicObject(Type type)
{
return typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type);
}

.NET - Omit Fields from JSON Web Service Call

I'm working on a .NET application for my company to interact with the Nutshell CRM. They have documentation provided for their JSON API here. I'm slowly building out all the classes in my application, but I've run into the issue of only needing to update one field on a call, but having the application include every field that I have on that class.
So for a condensed example of the editLead method, where I'm only modifying the customFields:
Nutshell documentation states that all fields are optional. My classes are set up as the following, where my custom fields in Nutshell are Division, Product, Country:
public class editLead
{
public Customfields customFields { get; set; }
}
public class Customfields
{
public string Division { get; set; }
public string Product { get; set; }
public string Country { get; set; }
}
EDIT (adding more code):
[DataContract(Name = "params")]
public class EditLeadParams
{
public string leadId { get; set; }
public editLead lead { get; set; }
public string rev { get; set; }
}
I'm using RestSharp to make the following call:
var editleadclient = new RestClient();
Method editleadMethod = new Method();
editleadMethod = Method.POST;
var editleadrequest = new RestRequest(editleadMethod);
editleadrequest.RequestFormat = DataFormat.Json;
editleadclient.BaseUrl = new Uri(apiuri);
editleadrequest.Credentials = new NetworkCredential(login, apikey);
leadJSON.EditLeadParams lead1 = new leadJSON.EditLeadParams()
{
leadId = foundlead[0],
lead = new leadJSON.editLead()
{
customFields = new leadJSON.Customfields()
{
Division = "AMERICAS",
}
},
rev = foundlead[1],
};
leadJSON.EditLeadRequest editreq = new leadJSON.EditLeadRequest()
{
#params = lead1,
method = "editLead",
};
editleadrequest.AddBody(editreq);
IRestResponse editResponse = editleadclient.Execute(editleadrequest);
If I only want to update the Division, it will use the following JSON {"customFields":{"Division":"AMERICAS","Product":null,"Country":null}}, and overwrite the Product and Country fields and make them blank. However, if I comment out the Product and Country, in the Customfields definition, it will update the Division and leave the Product and Country alone.
Is there another way to define these classes so that I can have it all defined, but only update what needs to be?
Declaration:
//JsonSerializer.cs
public static class JsonSerializer
{
public static string Serialize(object target, bool ignoreNulls = true)
{
var javaScriptSerializer = new JavaScriptSerializer();
if (ignoreNulls)
{
javaScriptSerializer.RegisterConverters(new[]
{
new NullExclusionConverter(target)
});
}
return javaScriptSerializer.Serialize(target);
}
}
//NullExclusionConverter.cs
public class NullExclusionConverter : JavaScriptConverter
{
private readonly Type _type;
public NullExclusionConverter(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this._type = target.GetType();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { this._type };
}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
if (obj == null)
{
return result;
}
var properties = obj.GetType().GetProperties();
foreach (var propertyInfo in properties)
{
//Use propertyInfo.Name to exclude a specific property name
if (propertyInfo.GetValue(obj, null) == null)
{
continue;
}
result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
}
return result;
}
}
Usage:
string jsonString = JsonSerializer.Serialize(objectToSerialize);
Add a reference to System.Web.Extensions
I am leaving my initial answer because it does return only non-null properties as a Json string. However here is your answer when using RestSharp.
On your request add:
editleadrequest.JsonSerializer.Options = new SerializerOptions()
{
SkipNullProperties = true
};

Remove the null property from object

,I have one class in which I have three properties now what I want to do, if in the object if any one of null or empty then I want to remove it from the object below is my code.
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
Now here I want the object of TestClass but in that Name and DateTime property should not be their in the object,
is it possible?
Please help me
There's no such concept as removing a property from an individual object. The type decided which properties are present - not individual objects.
In particular, it will always be valid to have a method like this:
public void ShowDateTime(TestClass t)
{
Console.WriteLine(t.DateTme);
}
That code has no way of knowing whether you've wanted to "remove" the DateTime property from the object that t refers to. If the value is null, it will just get that value - that's fine. But you can't remove the property itself.
If you're listing the properties of an object somewhere, you should do the filtering there, instead.
EDIT: Okay, no you've given us some context:
ok I am using Schemaless database so null and empty value also store space in database that's the reason
So in the code you're using which populates that database, just don't set any fields which corresponds to properties with a null value. That's purely a database population concern - not a matter for the object itself.
(I'd also argue that you should consider how much space you'll really save by doing this. Do you really care that much?)
I was bored and got this in LINQPad
void Main()
{
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
t.Dump();
var ret = t.FixMeUp();
((object)ret).Dump();
}
public static class ReClasser
{
public static dynamic FixMeUp<T>(this T fixMe)
{
var t = fixMe.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach(var pr in t.GetProperties())
{
var val = pr.GetValue(fixMe);
if(val is string && string.IsNullOrWhiteSpace(val.ToString()))
{
}
else if(val == null)
{
}
else
{
returnClass.Add(pr.Name, val);
}
}
return returnClass;
}
}
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
Hereby a 'slightly' more clear and shorter version of the accepted answer.
/// <returns>A dynamic object with only the filled properties of an object</returns>
public static object ConvertToObjectWithoutPropertiesWithNullValues<T>(this T objectToTransform)
{
var type = objectToTransform.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in type.GetProperties())
{
var value = propertyInfo.GetValue(objectToTransform);
var valueIsNotAString = !(value is string && !string.IsNullOrWhiteSpace(value.ToString()));
if (valueIsNotAString && value != null)
{
returnClass.Add(propertyInfo.Name, value);
}
}
return returnClass;
}
You could take advantage of the dynamic type:
class Program
{
static void Main(string[] args)
{
List<dynamic> list = new List<dynamic>();
dynamic
t1 = new ExpandoObject(),
t2 = new ExpandoObject();
t1.Address = "address1";
t1.ID = 132;
t2.Address = "address2";
t2.ID = 133;
t2.Name = "someName";
t2.DateTime = DateTime.Now;
list.AddRange(new[] { t1, t2 });
// later in your code
list.Select((obj, index) =>
new { index, obj }).ToList().ForEach(item =>
{
Console.WriteLine("Object #{0}", item.index);
((IDictionary<string, object>)item.obj).ToList()
.ForEach(i =>
{
Console.WriteLine("Property: {0} Value: {1}",
i.Key, i.Value);
});
Console.WriteLine();
});
// or maybe generate JSON
var s = JsonSerializer.Create();
var sb=new StringBuilder();
var w=new StringWriter(sb);
var items = list.Select(item =>
{
sb.Clear();
s.Serialize(w, item);
return sb.ToString();
});
items.ToList().ForEach(json =>
{
Console.WriteLine(json);
});
}
}
May be interfaces will be handy:
public interface IAdressAndId
{
int ID { get; set; }
string Address { get; set; }
}
public interface INameAndDate
{
string Name { get; set; }
DateTime? DateTime { get; set; }
}
public class TestClass : IAdressAndId, INameAndDate
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
Creating object:
IAdressAndId t = new TestClass()
{
Address = "address",
ID = 132,
Name = string.Empty,
DateTime = null
};
Also u can put your interfaces in separate namespace and make your class declaration as internal. After that create some public factories which will create the instances of your classes.

Categories

Resources