I was hoping to use a dynamically typed object to write to a CSV file.
I'm receiving a 'CsvHelper.CsvWriterException' within the CsvWriter.WriteObject method with this message: "No properties are mapped for type 'WpmExport.DynamicEntry'."
Here is the class that I'm trying use :
public class DynamicEntry : DynamicObject
{
private Dictionary<string, object> dictionary = new Dictionary<string, object>();
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
string name = binder.Name.ToLower();
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
dictionary[binder.Name.ToLower()] = value;
return true;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return dictionary.Keys.AsEnumerable();
}
}
Anyone with any ideas or working examples? The documentation at http://joshclose.github.io/CsvHelper/ hints that it is possible but doesn't provide any guidance.
TIA
The functionality does not exist yet. You can write dynamic but not DynamicObject. You can view a thread on the subject here. https://github.com/JoshClose/CsvHelper/issues/187
When the functionality get implemented, I'll update the answer with the version it's in.
Update
This functionality will be available in 3.0. You can currently try out the 3.0-beta from NuGet.
Because I cannot wait for Version 3.0 (and CsvHelper.Excel to support it), I have found a interim-solution.
Got the class to export:
public partial class EntryReportInventory
{
public Guid DeviceId { get; set; }
[ReportProperty]
public string DeviceName { get; set; }
public Dictionary<string, object> InventoryValues { get; set; }
public EntryReportInventory(Device device, Dictionary<string, object> inventoryValues)
{
this.DeviceId = device.Id;
this.DeviceName = device.Name;
this.InventoryValues = inventoryValues;
}
}
Created Mapper:
Type genericClass = typeof(DefaultCsvClassMap<>);
Type constructedClass = genericClass.MakeGenericType(typeof(EntryReportInventory));
return (CsvClassMap)Activator.CreateInstance(constructedClass);
And now the magic. I iterate all properties.
foreach (PropertyInfo property in mapping)
{
...
if (isInventoryReportBaseType && typeof(Dictionary<string, object>).IsAssignableFrom(property.PropertyType))
{
var dataSource = (ReportInventoryBase)Activator.CreateInstance(entityType, dbContext);
foreach (var item in dataSource.ColumnNameAndText)
{
var columnName = item.Key;
var newMap = new CsvPropertyMap(property);
newMap.Name(columnName);
newMap.TypeConverter(new InventoryEntryListSpecifiedTypeConverter(item.Key));
customMap.PropertyMaps.Add(newMap);
}
...
}
And my converter is:
public class InventoryEntryListSpecifiedTypeConverter : CsvHelper.TypeConversion.ITypeConverter
{
private string indexKey;
public InventoryEntryListSpecifiedTypeConverter(string indexKey)
{
this.indexKey = indexKey;
}
public bool CanConvertFrom(Type type)
{
return true;
}
public bool CanConvertTo(Type type)
{
return true;
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
throw new NotImplementedException();
}
public string ConvertToString(TypeConverterOptions options, object value)
{
var myValue = value as Dictionary<string, object>;
if (value == null || myValue.Count == 0) return null;
return myValue[indexKey] + "";
}
}
Don't know why, but it works to pass the same property several times.
That's it :)
You only have to have a list before (here: dataSource.ColumnNameAndText, filled from an external source) to identify the columns/values.
Related
I define a DynamicObject.
I have created a list of DynamicObjects with the same structure and link them to a WPF GridView.
I allow editing of some of the properties via the grid.
As the DynamicObjects present the property data as objects, how can I enforce Type restrictions?
if the user types alphabet into a cell that I would like as an int how can I get the DynamicObject to refuse the input?
You could use a TryParse wherever you're taking the cell input:
int result;
if(int.TryParse(cellText, out result))
{
// Is an integer
}
else
{
}
bool and other value types also have a TryParse if you're taking those values as well.
See also:
Comparing Types in this question
The DynamicDictionary example in the docs for a more verbose implementation on adding and editing properties.
In the constructor of my DynamicObject, I pass in with the properties definition, a dictionary of the types.
I then override the TrySetMember method to convert the value from the string supplied by the grid into its required type.
The issue I now have is sending a error message back to the grid if the conversion fails.
Here is My DynamicObject definition:
public sealed class FwDynamicObject : DynamicObject
{
private readonly Dictionary<string, object> _properties;
private readonly Dictionary<string, Type> _propertyTypes;
public FwDynamicObject(Dictionary<string, object> properties, Dictionary<string, Type> propertyTypes = null)
{
_properties = properties;
_propertyTypes = propertyTypes;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _properties.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_properties.ContainsKey(binder.Name))
{
result = _properties[binder.Name];
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_properties.ContainsKey(binder.Name))
{
var t = GetMemberType(binder.Name);
if (t != null)
{
try
{
value = Convert.ChangeType(value, t);
}
catch(Exception e)
{
return false;
}
}
_properties[binder.Name] = value;
return true;
}
else
{
return false;
}
}
private Type GetMemberType(string name)
{
if (_propertyTypes.ContainsKey(name))
{
return _propertyTypes[name];
}
return null;
}
}
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)
I use a template engine that renders templates from c# objects (nested). I would like to reflect and figure out which properties / objects are used in each template string.
An ideal way would be to build a "dummy" object representing the right shape and render this in the template. I would then inspect this object afterwards to find out which properties were accessed. This would allow me to keep this logic independant of the template library.
Any idea how i might implement this? The expando object is built dynamically like this:
var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in properties) {
dynamicObject.Add(property.Key,property.Value);
}
Had some ideas along these lines:
public class DummyObject {
public DummyObject() {
Accessed = new Dictionary<string, bool>();
}
public Dictionary<string, bool> Accessed;
object MyProp {
get {
Accessed["MyProp"] = true;
return "";
}
}
}
But this custom property obviously doesn't work with the dictionary / expando object. Any ideas of a route forward here?
You can override the TryGetMember method on DynamicObject:
public sealed class LoggedPropertyAccess : DynamicObject {
public readonly HashSet<string> accessedPropertyNames = new HashSet<string>();
public override bool TryGetMember(GetMemberBinder binder, out object result) {
accessedPropertyNames.Add(binder.Name);
result = "";
return true;
}
}
and then the following will output the accessed property names
dynamic testObject = new LoggedPropertyAccess();
string firstname = testObject.FirstName;
string lastname = testObject.LastName;
foreach (var propertyName in testObject.accessedPropertyNames) {
Console.WriteLine(propertyName);
}
Console.ReadKey();
N.B. There is still an issue here -- this works only as long as the template library expects only strings from the properties. The following code will fail, because every property will return a string:
DateTime dob = testObject.DOB;
In order to resolve this, and also allow for nested objects, have TryGetMember return a new instance of LoggedPropertyAccess. Then, you can override the TryConvert method as well; where you can return different values based on the conversion to different types (complete code):
using System;
using System.Collections.Generic;
using System.Dynamic;
namespace DynamicObjectGetterOverride {
public sealed class LoggedPropertyAccess : DynamicObject {
public readonly Dictionary<string, object> __Properties = new Dictionary<string, object>();
public readonly HashSet<string> __AccessedProperties = new HashSet<string>();
public override bool TryGetMember(GetMemberBinder binder, out object result) {
if (!__Properties.TryGetValue(binder.Name, out result)) {
var ret = new LoggedPropertyAccess();
__Properties[binder.Name] = ret;
result = ret;
}
__AccessedProperties.Add(binder.Name);
return true;
}
//this allows for setting values which aren't instances of LoggedPropertyAccess
public override bool TrySetMember(SetMemberBinder binder, object value) {
__Properties[binder.Name] = value;
return true;
}
private static Dictionary<Type, Func<object>> typeActions = new Dictionary<Type, Func<object>>() {
{typeof(string), () => "dummy string" },
{typeof(int), () => 42 },
{typeof(DateTime), () => DateTime.Today }
};
public override bool TryConvert(ConvertBinder binder, out object result) {
if (typeActions.TryGetValue(binder.Type, out var action)) {
result = action();
return true;
}
return base.TryConvert(binder, out result);
}
}
}
and use as follows:
using System;
using static System.Console;
namespace DynamicObjectGetterOverride {
class Program {
static void Main(string[] args) {
dynamic testObject = new LoggedPropertyAccess();
DateTime dob = testObject.DOB;
string firstname = testObject.FirstName;
string lastname = testObject.LastName;
dynamic address = testObject.Address;
address.House = "123";
address.Street = "AnyStreet";
address.City = "Anytown";
address.State = "ST";
address.Country = "USA";
WriteLine("----- Writes the returned values from reading the properties");
WriteLine(new { firstname, lastname, dob });
WriteLine();
WriteLine("----- Writes the actual values of each property");
foreach (var kvp in testObject.__Properties) {
WriteLine($"{kvp.Key} = {kvp.Value}");
}
WriteLine();
WriteLine("----- Writes the actual values of a nested object");
foreach (var kvp in testObject.Address.__Properties) {
WriteLine($"{kvp.Key} = {kvp.Value}");
}
WriteLine();
WriteLine("----- Writes the names of the accessed properties");
foreach (var propertyName in testObject.__AccessedProperties) {
WriteLine(propertyName);
}
ReadKey();
}
}
}
I have a scenario where I need the properties in my class to map to a dictionary. Here is a code sample:
public string Foo
{
get
{
if (!PropertyBag.ContainsKey("Foo"))
{
return null;
}
return PropertyBag["Foo"];
}
set
{
PropertyBag["Foo"] = value;
}
}
I have to apply this pattern to multiple properties. Is there a way to use attributes to do that?
I know that PostSharp would work for this purpose, but I was hoping there is a way to do it without using it.
This feels like a code smell to me. It would be better to use regular POCOs and convert them to a Dictionary only when needed.
public class BlogPost
{
public string Title { get; set; }
public string Body { get; set; }
public int AuthorId { get; set; }
public Dictionary<string, object> ToDictionary()
{
return this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(this, null));
}
}
Inspiration: How to convert class into Dictionary?
And to be honest, a ToDictionary method on your POCO's seems like a code smell. It would be better to refactor your code so the conversion of POCOs to Dictionaries happens in its own layer, as a service maybe.
Edit: This Gist I found while searching google for "c# convert object to dictionary" could provide a more generalized solution, and probably more bullet proof than my cobbled together example:
Gist: https://gist.github.com/jarrettmeyer/798667
From the Gist:
public static class ObjectToDictionaryHelper
{
public static IDictionary<string, object> ToDictionary(this object source)
{
return source.ToDictionary<object>();
}
public static IDictionary<string, T> ToDictionary<T>(this object source)
{
if (source == null)
ThrowExceptionWhenSourceArgumentIsNull();
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
{
object value = property.GetValue(source);
if (IsOfType<T>(value))
dictionary.add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
private static void ThrowExceptionWhenSourceArgumentIsNull()
{
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
}
}
Credit: jerrettmeyer at GitHub
This should add a ToDictionary method to every object.
Edit: From the following comment
To give a bit of context, I am using Entity Framework and I have a class hierarchy that I would like to keep in one table while avoiding null columns everywhere.
Entity framework supports multiple table inheritance. That might be a better solution in your case.
You can write a GetValueOrDefault extension method and reduce the code a little.
public static class DictionaryExtensions
{
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey,TValue> self, TKey key)
{
TValue value;
self.TryGetValue(key,out value);
return value;
}
}
public string Foo
{
get
{
return PropertyBag.GetValueOrDefault("Foo");
}
set
{
PropertyBag["Foo"] = value;
}
}
You can eliminate the magic strings using expressions.
If you're using at least .NET 4.5 then you have the CallerMemberNameAttribute which you could use like this:
class SomeClass
{
public string Foo
{
get
{
return GetPropertyValue();
}
set
{
SetPropertyValue( value );
}
}
private string GetPropertyValue( [CallerMemberName] string name = null )
{
string value;
PropertyBag.TryGetValue( name, out value );
return value;
}
private void SetPropertyValue( string value, [CallerMemberName] string name = null )
{
PropertyBag[name] = value;
}
}
This will result in the compiler filling out the name of the member for you. If you're not (or otherwise can't) use .NET 4.5, another alternative would be to take advantage of expression trees as suggested in another answer.
class Test
{
Dictionary<string,object> _values = new Dictionary<string, object>();
public string Foo
{
get
{
var value = GetValue();
return value == null ? string.Empty : (string)value;
}
set
{
SetValue(value);
}
}
private object GetValue()
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
if (_values.ContainsKey(key)) return _values[key];
return null;
}
private void SetValue(object value)
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
_values[key] = value;
}
private string GetGenericName(string key)
{
return key.Split('_')[1];
}
}
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);
}
}