Generic class to CSV (all properties) - c#

Im looking for a way to create CSV from all class instances.
What i want is that i could export ANY class (all of its instances) to CSV.
Can some1 direct me to possible solution for this (in case already anwsered).
thanx !

Have a look at LINQ to CSV. Although it's a little on the heavy side, which is why I wrote the following code to perform just the small subset of functionality that I needed. It handles both properties and fields, like you asked for, although not much else. One thing it does do is properly escape the output in case it contains commas, quotes, or newline characters.
public static class CsvSerializer {
/// <summary>
/// Serialize objects to Comma Separated Value (CSV) format [1].
///
/// Rather than try to serialize arbitrarily complex types with this
/// function, it is better, given type A, to specify a new type, A'.
/// Have the constructor of A' accept an object of type A, then assign
/// the relevant values to appropriately named fields or properties on
/// the A' object.
///
/// [1] http://tools.ietf.org/html/rfc4180
/// </summary>
public static void Serialize<T>(TextWriter output, IEnumerable<T> objects) {
var fields =
from mi in typeof (T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
where new [] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType)
let orderAttr = (ColumnOrderAttribute) Attribute.GetCustomAttribute(mi, typeof (ColumnOrderAttribute))
orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
select mi;
output.WriteLine(QuoteRecord(fields.Select(f => f.Name)));
foreach (var record in objects) {
output.WriteLine(QuoteRecord(FormatObject(fields, record)));
}
}
static IEnumerable<string> FormatObject<T>(IEnumerable<MemberInfo> fields, T record) {
foreach (var field in fields) {
if (field is FieldInfo) {
var fi = (FieldInfo) field;
yield return Convert.ToString(fi.GetValue(record));
} else if (field is PropertyInfo) {
var pi = (PropertyInfo) field;
yield return Convert.ToString(pi.GetValue(record, null));
} else {
throw new Exception("Unhandled case.");
}
}
}
const string CsvSeparator = ",";
static string QuoteRecord(IEnumerable<string> record) {
return String.Join(CsvSeparator, record.Select(field => QuoteField(field)).ToArray());
}
static string QuoteField(string field) {
if (String.IsNullOrEmpty(field)) {
return "\"\"";
} else if (field.Contains(CsvSeparator) || field.Contains("\"") || field.Contains("\r") || field.Contains("\n")) {
return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
} else {
return field;
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute {
public int Order { get; private set; }
public ColumnOrderAttribute(int order) { Order = order; }
}
}

Actually, something similar has been addressed here:
Best practices for serializing objects to a custom string format for use in an output file
Is this useful to you?
There is a sample that uses reflection to pull out the field names and values and append them to a string.

You can use reflection to traverse all the class properties/fields and write them to CSV.
A better approach would be to define a custom attribute and decorate the members you want to export and only export those attributes.

I am separating my answer into two sections:
The first one is how to export some generic item list into csv, with encoding, headers - (it will build csv data only for specified headers, and will ignore unneeded properties).
public string ExportCsv<T>(IEnumerable<T> items, Dictionary<string, string> headers)
{
string result;
using (TextWriter textWriter = new StreamWriter(myStream, myEncoding))
{
result = this.WriteDataAsCsvWriter<T>(items, textWriter, headers);
}
return result;
}
private string WriteDataAsCsvWriter<T>(IEnumerable<T> items, TextWriter textWriter, Dictionary<string, string> headers)
{
//Add null validation
////print the columns headers
StringBuilder sb = new StringBuilder();
//Headers
foreach (KeyValuePair<string, string> kvp in headers)
{
sb.Append(ToCsv(kvp.Value));
sb.Append(",");
}
sb.Remove(sb.Length - 1, 1);//the last ','
sb.Append(Environment.NewLine);
//the values
foreach (var item in items)
{
try
{
Dictionary<string, string> values = GetPropertiesValues(item, headers);
foreach (var value in values)
{
sb.Append(ToCsv(value.Value));
sb.Append(",");
}
sb.Remove(sb.Length - 1, 1);//the last ','
sb.Append(Environment.NewLine);
}
catch (Exception e1)
{
//do something
}
}
textWriter.Write(sb.ToString());
return sb.ToString();
}
//Help function that encode text to csv:
public static string ToCsv(string input)
{
if (input != null)
{
input = input.Replace("\r\n", string.Empty)
.Replace("\r", string.Empty)
.Replace("\n", string.Empty);
if (input.Contains("\""))
{
input = input.Replace("\"", "\"\"");
}
input = "\"" + input + "\"";
}
return input;
}
This is the most important function, Its extracting the properties values out of (almost) any generic class.
private Dictionary<string, string> GetPropertiesValues(object item, Dictionary<string, string> headers)
{
Dictionary<string, string> values = new Dictionary<string, string>();
if (item == null)
{
return values;
}
//We need to make sure each value is coordinated with the headers, empty string
foreach (var key in headers.Keys)
{
values[key] = String.Empty;
}
Type t = item.GetType();
PropertyInfo[] propertiesInfo = t.GetProperties();
foreach (PropertyInfo propertiyInfo in propertiesInfo)
{
//it not complex: string, int, bool, Enum
if ((propertiyInfo.PropertyType.Module.ScopeName == "CommonLanguageRuntimeLibrary") || propertiyInfo.PropertyType.IsEnum)
{
if (headers.ContainsKey(propertiyInfo.Name))
{
var value = propertiyInfo.GetValue(item, null);
if (value != null)
{
values[propertiyInfo.Name] = value.ToString();
}
}
}
else//It's complex property
{
if (propertiyInfo.GetIndexParameters().Length == 0)
{
Dictionary<string, string> lst = GetPropertiesValues(propertiyInfo.GetValue(item, null), headers);
foreach (var value in lst)
{
if (!string.IsNullOrEmpty(value.Value))
{
values[value.Key] = value.Value;
}
}
}
}
}
return values;
}
Example for GetPropertiesValues:
public MyClass
{
public string Name {get; set;}
public MyEnum Type {get; set;}
public MyClass2 Child {get; set;}
}
public MyClass2
{
public int Age {get; set;}
public DateTime MyDate {get; set;}
}
MyClass myClass = new MyClass()
{
Name = "Bruce",
Type = MyEnum.Sometype,
Child = new MyClass2()
{
Age = 18,
MyDate = DateTime.Now()
}
};
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Name", "CustomCaption_Name");
headers.Add("Type", "CustomCaption_Type");
headers.Add("Age", "CustomCaption_Age");
GetPropertiesValues(myClass, headers)); // OUTPUT: {{"Name","Bruce"},{"Type","Sometype"},{"Age","18"}}

My answer is based on Michael Kropat's answer from above.
I added two functions to his answer because it didn't want to write straight to file as I still had some further processing to do. Instead I wanted the header information separate to the values so I could put everything back together later.
public static string ToCsvString<T>(T obj)
{
var fields =
from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType)
let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
select mi;
return QuoteRecord(FormatObject(fields, obj));
}
public static string GetCsvHeader<T>(T obj)
{
var fields =
from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType)
let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
select mi;
return QuoteRecord(fields.Select(f => f.Name));
}

Related

C# | Create a json string out of static class fields with values

I need a method that will be able to loop through every static property in a static class, and combine these to a string with json syntax, where key name would equal to Property name, and key value would be the value of the property.
So the result would be a string with value:
{ "StaticPropertyName_string": "string_value_of_this_property", "StaticPropertyName_int": 34 }
I have a working method that successfully does the opposite - takes a json and maps data to static fields. But can't figure out how to do it in reverse
public static void MapProfileToJson(JToken source) //// source = plain json string
{
var destinationProperties = typeof(Fields)
.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (JProperty prop in source)
{
var destinationProp = destinationProperties
.SingleOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
var value = ((JValue)prop.Value).Value;
if (typeof(Fields).GetProperty(prop.Name) != null)
destinationProp.SetValue(null, Convert.ChangeType(value, destinationProp.PropertyType));
else
Console.WriteLine("(!) property \"" + prop.Name + "\" is not found in class... skip");
}
}
Example static class:
public static class Fields
{
public static bool BoolField { get; set; }
public static string StringField { get; set; }
public static int IntField { get; set; }
public static double DoubleField { get; set; }
}
p.s.
Key value pairs saved in string, could be wrapped at the end like
ResultString = "{ " + resultString + " }";
C# .NET 4.7.2 (console app)
As others have said, a static class is not a good design here.
However, it is possible to map it back to JSON with some simple reflection:
public static JObject MapStaticClassToJson(Type staticClassToMap)
{
var result = new JObject();
var properties = staticClassToMap.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in properties)
{
result.Add(new JProperty(prop.Name, prop.GetValue(null, null)));
}
return result;
}
I think it would be nice to have some simple code to assign json properties to a static class properties too. I created this code using #RichardDeeming answer
public static void MapStaticClassFromJson(string json, Type staticClassToMap)
{
var jsonObject = JObject.Parse(json);
var properties = staticClassToMap.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo prop in properties)
prop.SetValue(null, Convert.ChangeType(jsonObject[prop.Name], prop.PropertyType, CultureInfo.CurrentCulture), null);
}
test
MapStaticClassFromJson(json,typeof(Data));
Console.WriteLine(Data.StaticPropertyName_int);
Console.WriteLine(Data.StaticPropertyName_string);
result
34
string_value_of_this_property

FieldInfo update subfield of field

Good day,
I need to make function that will iterate on Dictionary that stores variable name and variable`s new value. After that, I need to update class variable with that value.
void UpdateValues(Type type, Dictionary<string, string> values)
{
foreach (var value in values)
{
var fieldInfo = selected.GetComponent(type).GetType().GetField(value.Key);
if (fieldInfo == null) continue;
fieldInfo.SetValue(selected.GetComponent(type), value.Value);
}
}
It works but I want little improvement and I absolutely don't know if it is possible.
As you can see, that function can accept any class, not just one specific.
If I have class like this
class test
{
public string age;
}
And I would use function this way, it would work.
UpdateValues(typeof(test), new Dictionary<string, string>{{"age", "17"}});
Problem is if I have class like this and I would like to update "subfield" (field in field)
class test
{
public string age;
}
class test2
{
public test data;
}
I was thinking that syntax could be something like this, but I have no idea how could I do it.
UpdateValues(typeof(test2), new Dictionary<string, string>{{"data.age", "17"}});
To sum it up, I need to make function that will take class that is stored in another class. Function will iterate trough the dictionary and update fields of class and even her subfields.
I would propose to add a recursive call to your method, to set the properties. I have changed your method a little bit, because i don't have selected object, it takes an object as a parameter
void UpdateValues<T>(T obj, Dictionary<string, string> values)
{
foreach (var value in values)
{
SetProperty(obj, value.Key, value.Value);
}
}
public void SetProperty<T>( T obj, string valueKey, string value, Type type= null)
{
var typeToUse = type ?? typeof(T);
var pointIndex = valueKey.IndexOf(".");
if (pointIndex!=-1)
{
var subKey = valueKey.Substring(0, pointIndex);
var fieldInfo = typeToUse.GetField(subKey);
var propObj = fieldInfo.GetValue(obj)
?? Activator.CreateInstance(fieldInfo.FieldType);
SetProperty(propObj, valueKey.Substring(pointIndex+1), value, fieldInfo.FieldType);
fieldInfo.SetValue(obj, propObj);
}
else
{
var fieldInfo = typeToUse.GetField(valueKey);
if (fieldInfo != null)
fieldInfo.SetValue(obj, value);
}
}
It works even if you define
class test3
{
public test2 data;
}
and call
UpdateValues(t, new Dictionary<string, string>{{"age", "17"}});
UpdateValues(t2, new Dictionary<string, string> { { "data.age", "17" } });
UpdateValues(t3, new Dictionary<string, string> { { "data.data.age", "17" } });
The third parameter of SetProperty method is not really nice, i would avoid it, but i don't know how to solve it with generics, after creating with Activator you get object as a Type, and object doesn't have field age
You are using Dictionary<string, string> as a parameter that allows you to set only string fields, so you must assume that you don't have any other. Actually this will work even if you will use Dictionary<string, object>, that i would suggest to do.
First of all you will need to change your Dictionary variable to use
Dictionary<string, object> if you want to pass a class as a parameter in here.
Secondly Here is an example of how to make it work.
class test
{
public string age;
}
class test2
{
public test data;
}
Lets suppose i have created an instance of test class and added it in a dictionary, to get the fields with reflection and then update the instance of test2 accordingly.
public void UpdateValues(object test2, Dictionary<string, object> dict)
{
var fieldValues = test2.GetType()
.GetFields()
.ToList();
foreach (var value in dict)
{
foreach (var field in fieldValues)
{
if (value.Key == field.Name)
{
bool obj = field.FieldType == typeof(test);
if (obj)
{
if (dict.ContainsKey("data"))
{
var prop = test2.GetType().GetField("data", System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance);
prop.SetValue(test2, dict["data"]);
break;
}
}
else
{
var prop = test2.GetType().GetField(value.Key, System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance);
prop.SetValue(test2, value.Value);
break;
}
}
}
}
}
In the end call you function i have created a Dictionary<string,object> instance to send it as a parameter to the function
object test2 = new test2();
test t = new test();
t.age = "10";
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("data", t);
UpdateValues(test2, dict);

Get class properties in C# (whitout instantiating it)

I've a class "TradingStrategy", with n subclasses ("Strategy1, Strategy2 etc...").
I've a simple UI from which i can choose a subclass (I've got all the subclasses of the "TradingStrategy" class pretty easily).
What i want now is to print (in a datagridview, listbox, combobox, doesn't matter) all the public parameters of the choosen subclass.
I would prefer not to instantiate the subclasses.
namespace BackTester
{
class TradingStrategy
{
public string Name;
}
class MA_Test : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 12;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test()
{
}
}
class MA_Test2 : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 24;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test2()
{
}
}
}
With this code i can insert into a combo box every subclass of "TradingStrategy"
var type = typeof(TradingStrategy);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var t in types){
if (t.Name == "TradingStrategy") continue;
boxStrategy.Items.Add(t.Name);
}
I wanna be able to, from the combobox.Text, get all the properties name and values of the corrisponding subclass.
I think I've read (and tried) every post here and in other forum. Many use reflections.
What is the simplest way to get those prop/values?
Thanks
Why not just create an interface ITradingStrategy:
public interface ITradingStrategy
{
string Name { get; }
int len { get; }
float lots { get; }
bool trendFollow { get; }
}
And have all classes inherit from the interface then pull values from interface.
As was mentioned in the comments, you have to instantiate an instance of the class in order to set some values on it.
To get the public fields/properties and their types without instantiating the objects, you can use reflection as follows:
private static Dictionary<string, Type> GetFields(Type t)
{
var fields = new Dictionary<string, Type>();
foreach (var memberInfo in t.GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
fields.Add(propertyInfo.Name, propertyInfo.PropertyType);
}
if (fieldInfo != null)
{
fields.Add(fieldInfo.Name, fieldInfo.FieldType);
}
}
return fields;
}
If you already have the object, you can get all the public fields/values with this method.
private static Dictionary<string, object> GetValues(FileInfo o)
{
var values = new Dictionary<string, object>();
foreach (var memberInfo in o.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
values.Add(propertyInfo.Name, propertyInfo.GetValue(o, null));
}
if (fieldInfo != null)
{
values.Add(fieldInfo.Name, fieldInfo.GetValue(o));
}
}
return values;
}
The following code is a very slow way to get all the types which derive from a given type, due to the way that the CLR implements GetTypes() and the fact there could be thousands of unrelated types in your code which makes the haystack to search even bigger. The only time you should use this method is if you dynamically load assemblies at runtime containing object definitions that you need to load. Unfortunately there is no other way to get this information at runtime:
var type = typeof(TradingStrategy);
var subtypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => p != type && type.IsAssignableFrom(p));
I would recommend that you store this list of types somewhere in your code, e.g. in an array, and iterate over it when you need to know all of your strategies:
private static readonly Type[] TradingStrategies =
{
typeof(Strategy1),
typeof(Strategy2),
typeof(Strategy3),
};
After reading Erik's answer. If you will never instantiate these classes, you could store this data in a configuration file, and use something like JSON.net to read it, or if you don't want to use an external library, XmlSerializer would work as well. In this case you would store each MATest as a Dictionary (which lends itself nicely to JSON.net's JObject. Using JSON.net, you would have a configuration file that looks like:
[
{
"MA_Test": {
"len": 12,
"lots": 0.1,
"trendFollow": true
},
"MA_Test2": {
"len": 24,
"lots": 0.1,
"trendFollow": true
}
}
]
Then read it with code that looks like:
public JObject ReadConfig(string configPath)
{
using (var filestream = File.Open(configPath, FileMode.Open))
using (var streamReader = new StreamReader(filestream))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
var jsonSerializer = new JsonSerializer();
return jsonSerializer.Deserialize<JObject>(jsonTextReader);
}
}
Thank you all for you answers.
The simplest way I found to get the properties from an indirected instantiated class is this:
var strategy = activator.CreateInstance(Type.GetType("BackTester."+boxStrategy.Text));
foreach (FieldInfo prop in strategy.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance))
{
listBox1.Items.Add(prop.ToString() + " " + prop.GetValue(strategy));
}
Based on the code you've provided, there is no reason for there to be separate classes for each MA_Test (X DO NOT use underscores, hyphens, or any other nonalphanumeric characters.). Instead these should be the same class with different properties (not fields).
class TradingStrategy
{
public string Name { get; set; }
}
class MATest : TradingStrategy
{
// this is not needed if it is inherited by TradingStragegy
// You should be getting a warning that you are hiding
// the field/property
// public string Name { get; set; }
// Should probably be more descriptive
// e.g. LengthInFeet...
public int Length { get; set; }
public float Lots { get; set; }
// I recommended boolean properties to be prefixed with
// Is, Can, Has, etc
public bool CanTrendFollow { get; set; }
}
// Somewhere Else...
var MATests = new List<MATest>()
{
new MATest()
{
Name = "MATest",
Length = 12,
Lots = 0.1F,
CanTrendFollow = true
},
new MATest()
{
Name = "MATest",
Length = 24,
Lots = 0.1F,
CanTrendFollow = true
},
}
Now instead of costly Reflection and Activator, just create the list classes once (manually, from config or even a database), and they can be used for whatever you need.

Newly created item field values

When creating a new item; is there any way to access all the field values that are set.
Since I'm using Entity.GetModifiedMembers() method to access the values of the fields that are changed when updating for logging purposes, the purpose is to have the equivalent result through an entity when creating, like a method Entity.GetSetMembers().
So in general, all I need is a key-value pair with "member name" and "value" items.
Example:
public class SomethingEntity
{
public int Id {get;set;}
public string Name {get;set;}
public DateTime Created {get;set;}
public DateTime Modified {get;set;}
}
public Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object entity)
{
//This is what I need, that can take all the objects from an entity and give
//the property-value pairs for the object instance
return RequieredMethod(entity);
}
public ExampleMethod()
{
var newObject = new SomethingEntity() { Name = "SomeName", Created = DateTime.Now };
Entity.insetOnSubmit(newObject);
Entity.SubmitChanges();
var resultList = GetFieldsAndValuesOfCreatedItem(newObject);
foreach (var propertyKeyValue in resultList)
{
var propertyString = "Property Name: " + propertyKeyValue.Key;
var valueString = "Value : " + propertyKeyValue.Value;
}
}
I've found out that, Reflection is the answer for that as far as I could find: so here is the method I've come up with:
public static Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object item)
{
var propertyInfoList = item.GetType().GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
var list = new Dictionary<string, string>();
foreach (var propertyInfo in propertyInfoList)
{
var valueObject = propertyInfo.GetValue(item, null);
var value = valueObject != null ? valueObject.ToString() : string.Empty;
if (!string.IsNullOrEmpty(value))
{
list.Add(propertyInfo.Name, value);
}
}
return list;
}

How to convert variable name to string in c#.net? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
public new Dictionary<string, string> Attributes { get; set; }
public string StringAttributes = string.Empty;
public int? MaxLength { get; set; }
public int? Size { get; set; }
public int? Width { get; set; }
public int? Height { get; set; }
protected override void OnInit(EventArgs e) {
Attributes = new Dictionary<string, string>();
Attributes.Add("MaxLength", MaxLength.ToString());
Attributes.Add("Size", Size.ToString());
Attributes.Add("Width", Width.ToString());
Attributes.Add("Height", Height.ToString());
base.OnInit(e);
}
protected override void OnPreRender(EventArgs e) {
if (Attributes != null) {
StringBuilder attributes = new StringBuilder();
foreach (var item in Attributes) {
if (!string.IsNullOrWhiteSpace(item.Value)) {
attributes.Append(item.Key + "=\"" + item.Value + "\" ");
}
}
StringAttributes = attributes.ToString();
}
}
The problem here is, instead of using Attributes.Add("MaxLength", MaxLength.ToString()); and repeat the same process for other properties, could we not just make a function that is also able to add values to the dictionary, where the keys to be added are their variable names?
Say,
public void addAttribute(object variable){
Attributes = new Dictionary<string, string>();
Attributes.Add(variable.Name, variable.Value);
}...
I guess this is also possible to do with reflection, getting all the nullable properties and looping through them then adding each to the dictionary... But for as long as there are any other ways, we would not stick to reflection.
But if reflection is the only choice, then another problem now would be how to get the nullable properties of the class...
Any help would be greatly appreciated. Thank you.
I can't think of way to do it without reflection.
In order to get all the nullable properties you can you similar code to this:
GetType().GetProperties()
.Where(property =>
property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
Usage example that fills attributes dictionary:
PropertyInfo[] typeProperties = GetType().GetProperties();
var nullableProperties = typeProperties.Where(property =>
property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>));
var attributes = new Dictionary<string, string>();
foreach (var nullableProperty in nullableProperties)
{
object value = nullableProperty.GetValue(this,null);
attributes.Add(nullableProperty.Name, value == null ?
string.Empty : value.ToString());
}
I'm not sure I fully understand your question without more context, but perhaps this is helpful
If the concern is over reflection overhead for multiple invocations:
Cache that information.
try EmitMapper to fill in values
try AutoMapper to fill in the values
If the problem is getting a variable name via strongly typed compilation then you can use
The Member class I saw on a post from Oliver Hhanappi. Examples of its use are here on my blog
Below is my complete solution. I would say your best bet is to use reflection, as what you're asking is sort of a meta-task. As far as how do you know which properties to add, I would suggest defining your own attribute and applying it to the fields/properties that you want to inspect.
Usage:
Dictionary<string, string> attributes = Inspector<MyClass>.Inspect(target);
The reflection in my sample code is executed once per type inspected, as it is executed within the static constructor of my generic Inspect class:
// apply this attribute to any properties or fields that you want added to the attributes dictionary
[AttributeUsage(
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Interface,
AllowMultiple = true, Inherited = true)]
public class InspectAttribute : Attribute
{
// optionally specify the member name explicitly, for use on classes, structs, and interfaces
public string MemberName { get; set; }
public InspectAttribute() { }
public InspectAttribute(string memberName)
{
this.MemberName = memberName;
}
}
public class Inspector<T>
{
// Inspector is a generic class, therefore there will be a separate instance of the _InspectActions variable per type
private static List<Action<Dictionary<string, string>, T>> _InspectActions;
static Inspector()
{
_InspectActions = new List<Action<Dictionary<string, string>, T>>();
foreach (MemberInfo m in GetInspectableMembers(typeof(T)))
{
switch (m.MemberType)
{
case MemberTypes.Property:
{
// declare a separate variable for variable scope with anonymous delegate
PropertyInfo member = m as PropertyInfo;
// create an action delegate to add an entry to the attributes dictionary using the property name and value
_InspectActions.Add(
delegate(Dictionary<string, string> attributes, T item)
{
object value = member.GetValue(item, null);
attributes.Add(member.Name, (value == null) ? "[null]" : value.ToString());
});
}
break;
case MemberTypes.Field:
{
// declare a separate variable for variable scope with anonymous delegate
FieldInfo member = m as FieldInfo;
// need to create a separate variable so that delegates do not share the same variable
// create an action delegate to add an entry to the attributes dictionary using the field name and value
_InspectActions.Add(
delegate(Dictionary<string, string> attributes, T item)
{
object value = member.GetValue(item);
attributes.Add(member.Name, (value == null) ? "[null]" : value.ToString());
});
}
break;
default:
// for all other member types, do nothing
break;
}
}
}
private static IEnumerable<MemberInfo> GetInspectableMembers(Type t)
{
// get all instance fields and properties
foreach (MemberInfo member in t.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.GetProperty))
{
// check if the current member is decorated with an Inspect attribute
object[] inspectAttributes = member.GetCustomAttributes(typeof(InspectAttribute), true);
if (inspectAttributes != null && inspectAttributes.Length > 0)
{
yield return member;
}
}
// now look for any Inspect attributes defined at the type level
InspectAttribute[] typeLevelInspectAttributes = (InspectAttribute[])t.GetCustomAttributes(typeof(InspectAttribute), true);
if (typeLevelInspectAttributes != null && typeLevelInspectAttributes.Length > 0)
{
foreach (InspectAttribute attribute in typeLevelInspectAttributes)
{
// search for members matching the name provided by the Inspect attribute
MemberInfo[] members = t.GetMember(attribute.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy);
if (members != null && members.Length > 0)
{
foreach (MemberInfo member in members)
{
yield return member;
}
}
}
}
}
public static Dictionary<string, string> Inspect(T item)
{
// create a new attributes dictionary
Dictionary<string, string> attributes = new Dictionary<string, string>();
foreach (Action<Dictionary<string, string>, T> inspectAction in _InspectActions)
{
// execute each "inspect" action.
// This will execute the delegates we created earlier, causing entries to be added to the dictionary
inspectAction(attributes, item);
}
return attributes;
}
}
public class BasePage
{
public int? SomeValue { get; set; }
}
// example class with properties decorated with the Inspect attribute
[Inspect("SomeValue")] // also inspect the "SomeValue" property from the BasePage class
public class MyPage : BasePage
{
[Inspect]
public int? MaxLength { get; set; }
[Inspect]
public int? Size { get; set; }
[Inspect]
public int? Width { get; set; }
[Inspect]
public int? Height { get; set; }
public string GenerateAttributeString()
{
System.Text.StringBuilder attributes = new System.Text.StringBuilder();
foreach (KeyValuePair<string, string> item in Inspector<MyPage>.Inspect(this))
{
attributes.Append(item.Key + "=\"" + item.Value + "\" ");
}
return attributes.ToString();
}
}
You can use the following function to extract out the public Nullable properties from a class into the format your looking for. It also calls the getter method for the value.
This is using the same reflection use that #Elisha talked about. Also it does a .ToString() call to the value returned by the getter.
IDictionary<string, string> GetProps<T>(T DataObject)
{
if(null == DataObject)
return new Dictionary<string, string>();
var nullableProperties =
from property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
from accessor in property.GetAccessors(false)
let returnType = accessor.ReturnType
where returnType.IsGenericType
&& returnType.GetGenericTypeDefinition() == typeof(Nullable<>)
&& accessor.GetParameters().Length == 0
select new { Name=property.Name, Getter=accessor};
return nullableProperties.ToDictionary(
x => x.Name,
x => x.Getter.Invoke(DataObject, null).ToString());
}

Categories