Generic Converters for struct to class and vice versa - c#

I want to have two converters like these:
public class PacMan<T2> where T2 : new()
{
public static List<T1> ArrayToList<T1>(T2[] array)
{
var list = new List<T1>(array.Length);
for (int i = 0; i < array.Length; i++) list.Add(array[i]);
return list;
}
public static T2[] ListToArray<T1>(List<T1> list)
{
var array = new T2[list.Count];
for (int i = 0; i < list.Count; i++) array[i] = list[i];
return array;
}
}
where T1 is a class and T2 is a struct. Both the class and struct members have Identical names and types. With the above I get red squigly in first method's list.Add(array[i]) and second methods array[i] = list[i] so these don't work. What's the easiest way to do that?
EDIT
Here's the class:
public class PerSec : INotifyPropertyChanged
{
string yq;
float eps, nav, cash, debt;
public string YQ { get => yq; set { yq = value; OnPropertyChanged(); } }
public float EPS { get => eps; set { eps = value; OnPropertyChanged(); } }
public float NAV { get => nav; set { nav = value; OnPropertyChanged(); } }
public float Cash { get => cash; set { cash = value; OnPropertyChanged(); } }
public float Debt { get => debt; set { debt = value; OnPropertyChanged(); } }
#region Notify Property Changed Members
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
#endregion
}
and here's the struct:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PerSecStruct
{
//23 bytes
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
public string YQ;
public float EPS;
public float NAV;
public float Cash;
public float Debt;
}
EDIT
In second method, I've these now:
public static T2[] ListToarray<T1>(List<T1> list)
{
var structFields = typeof(PerSecStruct).GetFields(BindingFlags.Instance | BindingFlags.Public);
var classFields = typeof(PerSec).GetProperties(BindingFlags.Instance | BindingFlags.Public);
classFields = classFields.Where(x => structFields.Select(y => y.Name).Contains(x.Name)).ToArray();
var fieldsDictionary = structFields.Zip(classFields, (k, v) => new { StructField = k, ClassField = v }).ToDictionary(x => x.StructField, x => x.ClassField);
var array = new T2[list.Count];
for (int i = 0; i < list.Count; i++)
{
var psStruct = array[i];
var psClass = list[i];
foreach (var entry in fieldsDictionary)
{
var value = entry.Value.GetValue(psClass);
entry.Key.SetValue(psStruct, value);
}
}
return array;
}
this entry.Key.SetValue(psStruct, value); line isn't working so the elements of array have their default values (null/0).
EDIT
It works if I use __makeref(array[i]) as noted here by petelids. With that I can do this:
public static T2[] ListToarray<T1>(List<T1> list)
{
var fields = typeof(T2).GetFields();
var properties = typeof(T1).GetProperties();
var array = new T2[list.Count];
for (int i = 0; i < list.Count; i++)
{
foreach (var field in fields)
{
var value = properties.First(x => x.Name == field.Name).GetValue(list[i]);
field.SetValueDirect(__makeref(array[i]), value);
}
}
return array;
}
I don't need those Binding Flags! And to convert back to List I've to do this in other method:
public static List<T1> ArrayToList<T1>(T2[] array) where T1 : new()
{
var fields = typeof(T2).GetFields();
var properties = typeof(T1).GetProperties();
var list = new List<T1>(array.Length);
for (int i = 0; i < array.Length; i++)
{
var obj = new T1();
foreach (var property in properties)
{
var value = fields.First(x => x.Name == property.Name).GetValue(array[i]);
property.SetValue(obj, value);
}
list.Add(obj);
}
return list;
}

You could use most of serializers for that, for example with Json.NET:
using Newtonsoft.Json;
...
internal static class MyConverter
{
internal static T Convert<T>(object source)
{
string json = JsonConvert.SerializeObject(source);
T result = JsonConvert.DeserializeObject<T>(json);
return result;
}
}
usage:
var s1 = new PerSecStruct { YQ = "1", EPS = 2, NAV = 3, Cash = 4, Debt = 5 };
// to object
var o = MyConverter.Convert<PerSec>(s1);
// back to struct
var s2 = MyConverter.Convert<PerSecStruct>(o);

This can be done using Reflection, although I also highly advise you look at AutoMapper as Knoop pointed out in the comments, but if you only need it for this one struct you could code your own implementation.
Reflection "is the ability of a process to examine, introspect, and modify its own structure and behaviour", in C# we use the System.Reflection namespace for this.
So we want to map all public fields of one struct to all public properties of another, for this we first need to get all public fields on our struct and all the properties on our class like so:
(For this we need an instance of each)
var psStruct = ...;
var psClass =...;
// BindingFlags.Instance means all instance fields (non-static)
// BindingFlags.Public means only public fields
var structFields = typeof(PerSecStruct).GetFields(BindingFlags.Instance | BindingFlags.Public);
// The BindingFlags are the same, but we use 'GetProperties' because you declared properties not fields
var classFields = typeof(PerSec).GetProperties(BindingFlags.Instance | BindingFlags.Public);
So now we have a list of both the fields on the struct and the Properties on the class, so we can actually begin mapping:
// First filter the list on the Class to make sure we only have properties the struct has as well
classFields = classFields.Where(x => structFields.Select(y => y.Name).Contains(x.Name));
// ToDictionary to combine both lists into one
var fieldsDictionary = structFields.Zip(classFields, (k, v) => new {StructField = k, ClassField = v}).ToDictionary(x => x.StructField, x => x.ClassField);
foreach (var entry in fieldsDictionary)
{
// Get the value from the psStruct object
var value = entry.Key.GetValue(psStruct);
// Set value on the psClass object (this can be a one-liner but I prefer this as it is more readable)
entry.Value.SetValue(psClass, value);
}
A concrete example of how to use this:
public static List<TTarget> As<TSource>(IEnumerable<TSource> source) where TTarget : new();
{
var sourceFields = typeof(TSource).GetFields(BindingFlags.Instance | BindingFlags.Public);
var targetProperties = typeof(TTarget).GetProperties(BindingFlags.Instance | BindingFlags.Public);
var mapping = sourceFields.Zip(targetProperties, (k, v) => new {Source = k, Target = v}).ToDictionary(x => x.Source, x => x.Target);
var retval = new List<TTarget>();
foreach (var sourceObject in source)
{
var mappedObject = new TTarget();
foreach (var m in mapping)
{
var value = entry.Key.GetValue(sourceObject);
entry.Value.SetValue(mappedObject, value);
}
retval.Add(mappedObject);
}
return retval;
}
I added an OrderBy clause to getting the struct/ class fields/ Properties because else the order or declaration inside the struct/ class would have had to have been the same, like this it doesn't matter.
This currently does not work both ways, but if you decide to replace the fields inside your struct with Properties you can replace the typeof(TSource).GetFields(...) with typeof(TSource).GetProperties(...), then it would work both ways

Related

Replicating dynamic multi-dimensional array creation of PHP

So, I am converting a project from PHP to C#. Got a Generic List of data as a result of a query
//C# code
public class TermsCommodityModel
{
public int terms_id { get; set; }
public int commodity_id { get; set; }
public int custom { get; set; }
public int calculated { get; set; }
public string name { get; set; }
public string formula { get; set; }
public int division_id { get; set; }
}
I was able to populate it into termsTable which is a List<TermsCommodityModel>. Then the PHP code started looping the termsTable.( C# and PHP codes use same variable for easy conversion). The first line completely altered my datastructure
//PHP code
if (!isset($termsTable[$name]))
$termsTable[$name] = array();
I thought, weird but doable. Then the second condition created another child array and it went on. Now the PHP code looks so,
//PHP Code
if (!isset($termsTable[$name][$t->commodity_id]))
$termsTable[$name][$t->commodity_id] = array();
//.Omitted for brevity
//....
$year = date("Y") + 5;
for ($y = 2008; $y<= $year; $y++) {
$termsTable[$name][$t->commodity_id][$y] = array();
for ($i=1; $i<=12; $i++)
$termsTable[$name][$t->commodity_id][$y][$i] = 0;
}
This is the final data-structure
//PHP Code
$termsTable[$name]
$termsTable[$name][$t->commodity_id]
$termsTable[$name][$t->commodity_id][$y]
$termsTable[$name][$t->commodity_id][$y][$i]
This essentially created an array of an array of an array of an array of an object dynamically. The thing is PHP is a dynamically typed language. It doesn't need to specify a type
Which data-structure in C# could possibly do this? Cant use a tuple as they are hierarchical, right?
Which way to approach this? Any pointers will be extremely helpful as this is kinda important.
I'm not sure how TermsCommodityModel is related to php code, because it's not shown anywhere there as far as I can tell. Anyway, you can achieve syntax similar to php by (ab)using dynamic and DynamicObject. First create class like this:
public class DynamicDictionary : DynamicObject {
private readonly Dictionary<object, object> _dictionary;
public DynamicDictionary() {
_dictionary = new Dictionary<object, object>();
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
// this will be called when you do myDict[index] (but not myDict[index] = something)
if (indexes.Length != 1)
throw new Exception("Only 1-dimensional indexer is supported");
var index = indexes[0];
// if our internal dictionary does not contain this key
// - add new DynamicDictionary for that key and return that
if (_dictionary.ContainsKey(index)) {
_dictionary.Add(index, new DynamicDictionary());
}
result = _dictionary[index];
return true;
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) {
// this will be called when you do myDict[index] = value
if (indexes.Length != 1)
throw new Exception("Only 1-dimensional indexer is supported");
var index = indexes[0];
// just set value
_dictionary[index] = value;
return true;
}
}
And use it like this:
dynamic termsTable = new DynamicDictionary();
var name = "name";
int commodityId = 123;
var year = DateTime.Now.Year + 5;
for (int y = 2008; y <= year; y++) {
for (int i = 1; i < 12; i++) {
// that's fine
termsTable[name][commodityId][y][i] = 0;
}
}
// let's see what we've got:
for (int y = 2008; y <= year; y++) {
for (int i = 1; i < 12; i++) {
// that's fine
Console.WriteLine(termsTable[name][commodityId][y][i]);
}
}
To mirror your php code even more, change TryGetIndex like this:
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
// this will be called when you do myDict[index] (but not myDict[index] = something)
if (indexes.Length != 1)
throw new Exception("Only 1-dimensional indexer is supported");
var index = indexes[0];
// if our internal dictionary does not contain this key
// return null
if (!_dictionary.ContainsKey(index)) {
result = null;
}
else {
result = _dictionary[index];
}
return true;
}
Then you need to check if such key already exists (which is a bit better to my mind):
dynamic termsTable = new DynamicDictionary();
var name = "name";
int commodityId = 123;
var year = DateTime.Now.Year + 5;
// need to check if such key exists
// like isset in php
if (termsTable[name] == null)
termsTable[name] = new DynamicDictionary();
if (termsTable[name][commodityId] == null)
termsTable[name][commodityId] = new DynamicDictionary();
for (int y = 2008; y <= year; y++) {
if (termsTable[name][commodityId][y] == null)
termsTable[name][commodityId][y] = new DynamicDictionary();
for (int i = 1; i < 12; i++) {
// that's fine
termsTable[name][commodityId][y][i] = 0;
}
}
Of course type safery is thrown out of the window by doing that, but if you are fine with that - why not.
Although the code in my first answer reproduces the original logic written in PHP, it lacks some very important qualities. It is not self-explanatory, and it is hard to read.
Specifically, things like Dictionary<string, Dictionary<int, Dictionary<int, Dictionary<int, int>>>> is a huge anti-pattern. No one knows what is expected to be in the keys and in the values of this monster data structure. It is too error-prone.
A much better way to factor the code would be as follows:
public class TermsTable
{
private readonly Dictionary<string, IndexByCommodityId> _index;
public TermsTable(IEnumerable<TermsCommodityModel> list)
{
_index = list
.GroupBy(tcm => tcm.name)
.ToDictionary(
tcmGroup => tcmGroup.Key,
tcmGroup => new IndexByCommodityId(tcmGroup));
}
public IndexByCommodityId this[string name] => _index[name];
}
public class IndexByCommodityId
{
private readonly Dictionary<int, IndexByYear> _index;
public IndexByCommodityId(IEnumerable<TermsCommodityModel> list)
{
_index = list.ToDictionary(
keySelector: tcm => tcm.commodity_id,
elementSelector: tcm => new IndexByYear());
}
public IndexByYear this[int commodityId] => _index[commodityId];
}
public class IndexByYear
{
private static readonly int _nowYear = DateTime.Now.Year;
private readonly Dictionary<int, IndexByMonth> _index;
public IndexByYear()
{
_index = Enumerable
.Range(2008, _nowYear - 2008 + 1)
.ToDictionary(
keySelector: year => year,
elementSelector: year => new IndexByMonth());
}
public IndexByMonth this[int year] => _index[year];
}
public class IndexByMonth
{
private readonly Dictionary<int, int> _index;
public IndexByMonth()
{
_index = Enumerable.Range(1, 12).ToDictionary(month => month, month => 0);
}
public int this[int month]
{
get => _index[month];
set => _index[month] = value;
}
}
The code that uses the new data structure would look like this:
// a flat list of TermsCommodityModel, filled with data elsewhere
List<TermsCommodityModel> list = new List<TermsCommodityModel>();
// create our hierarchical index from the above list
TermsTable aBetterTermsTable = new TermsTable(list);
string name = "ABC";
int commodityId = 12345;
int year = 2010;
int month = 10;
int value = aBetterTermsTable[name][commodityId][year][month];
Yes, it is much more code to write, but its worth it. It is easier to read, and less error prone. For instance, one of the benefits is IntelliSense:
I have little knowledge in PHP, but it looks like I can follow. The code you demonstrate in your question is based on associative arrays. In .NET, associative arrays are usually implemented through Dictionary<TKey, TValue> data structure.
You start with a flat List<TermsCommodityModel>, and then you can build hierarchical dictionary-based structures as follows:
// a flat list of TermsCommodityModel, filled with data elsewhere
List<TermsCommodityModel> list = new List<TermsCommodityModel>();
Dictionary<string, Dictionary<int, Dictionary<int, Dictionary<int, int>>>> termsTable = list
.GroupBy(tcm => tcm.name)
.ToDictionary(
tcmGroup => tcmGroup.Key,
tcmGroup => tcmGroup.ToDictionary(
tcm => tcm.commodity_id,
tcm => CreateYearMonthTable()));
and one more helper function:
static Dictionary<int, Dictionary<int, int>> CreateYearMonthTable()
{
var year = DateTime.Now.Year + 5;
return Enumerable
.Range(2008, year - 2008 + 1)
.ToDictionary(
y => y,
y => Enumerable.Range(1, 12).ToDictionary(i => i, i => 0));
}
the following is an example of how you access the leaf values in this data structure:
string name = "ABC";
int commodityId = 12345;
int year = 2010;
int month = 10;
int value = termsTable[name][commodityId][year][month];
EDIT
A better approach to solve the problem is in my second answer:
https://stackoverflow.com/a/47593724/4544845

Compare Properties automatically

I want to get the names of all properties that changed for matching objects. I have these (simplified) classes:
public enum PersonType { Student, Professor, Employee }
class Person {
public string Name { get; set; }
public PersonType Type { get; set; }
}
class Student : Person {
public string MatriculationNumber { get; set; }
}
class Subject {
public string Name { get; set; }
public int WeeklyHours { get; set; }
}
class Professor : Person {
public List<Subject> Subjects { get; set; }
}
Now I want to get the objects where the Property values differ:
List<Person> oldPersonList = ...
List<Person> newPersonList = ...
List<Difference> = GetDifferences(oldPersonList, newPersonList);
public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP) {
//how to check the properties without casting and checking
//for each type and individual property??
//can this be done with Reflection even in Lists??
}
In the end I would like to have a list of Differences like this:
class Difference {
public List<string> ChangedProperties { get; set; }
public Person NewPerson { get; set; }
public Person OldPerson { get; set; }
}
The ChangedProperties should contain the name of the changed properties.
I've spent quite a while trying to write a faster reflection-based solution using typed delegates. But eventually I gave up and switched to Marc Gravell's Fast-Member library to achieve higher performance than with normal reflection.
Code:
internal class PropertyComparer
{
public static IEnumerable<Difference<T>> GetDifferences<T>(PropertyComparer pc,
IEnumerable<T> oldPersons,
IEnumerable<T> newPersons)
where T : Person
{
Dictionary<string, T> newPersonMap = newPersons.ToDictionary(p => p.Name, p => p);
foreach (T op in oldPersons)
{
// match items from the two lists by the 'Name' property
if (newPersonMap.ContainsKey(op.Name))
{
T np = newPersonMap[op.Name];
Difference<T> diff = pc.SearchDifferences(op, np);
if (diff != null)
{
yield return diff;
}
}
}
}
private Difference<T> SearchDifferences<T>(T obj1, T obj2)
{
CacheObject(obj1);
CacheObject(obj2);
return SimpleSearch(obj1, obj2);
}
private Difference<T> SimpleSearch<T>(T obj1, T obj2)
{
Difference<T> diff = new Difference<T>
{
ChangedProperties = new List<string>(),
OldPerson = obj1,
NewPerson = obj2
};
ObjectAccessor obj1Getter = ObjectAccessor.Create(obj1);
ObjectAccessor obj2Getter = ObjectAccessor.Create(obj2);
var propertyList = _propertyCache[obj1.GetType()];
// find the common properties if types differ
if (obj1.GetType() != obj2.GetType())
{
propertyList = propertyList.Intersect(_propertyCache[obj2.GetType()]).ToList();
}
foreach (string propName in propertyList)
{
// fetch the property value via the ObjectAccessor
if (!obj1Getter[propName].Equals(obj2Getter[propName]))
{
diff.ChangedProperties.Add(propName);
}
}
return diff.ChangedProperties.Count > 0 ? diff : null;
}
// cache for the expensive reflections calls
private Dictionary<Type, List<string>> _propertyCache = new Dictionary<Type, List<string>>();
private void CacheObject<T>(T obj)
{
if (!_propertyCache.ContainsKey(obj.GetType()))
{
_propertyCache[obj.GetType()] = new List<string>();
_propertyCache[obj.GetType()].AddRange(obj.GetType().GetProperties().Select(pi => pi.Name));
}
}
}
Usage:
PropertyComparer pc = new PropertyComparer();
var diffs = PropertyComparer.GetDifferences(pc, oldPersonList, newPersonList).ToList();
Performance:
My very biased measurements showed that this approach is about 4-6 times faster than the Json-Conversion and about 9 times faster than ordinary reflections. But in fairness, you could probably speed up the other solutions quite a bit.
Limitations:
At the moment my solution doesn't recurse over nested lists, for example it doesn't compare individual Subject items - it only detects that the subjects lists are different, but not what or where. However, it shouldn't be too hard to add this feature when you need it. The most difficult part would probably be to decide how to represent these differences in the Difference class.
We start with 2 simple methods:
public bool AreEqual(object leftValue, object rightValue)
{
var left = JsonConvert.SerializeObject(leftValue);
var right = JsonConvert.SerializeObject(rightValue);
return left == right;
}
public Difference<T> GetDifference<T>(T newItem, T oldItem)
{
var properties = typeof(T).GetProperties();
var propertyValues = properties
.Select(p => new {
p.Name,
LeftValue = p.GetValue(newItem),
RightValue = p.GetValue(oldItem)
});
var differences = propertyValues
.Where(p => !AreEqual(p.LeftValue, p.RightValue))
.Select(p => p.Name)
.ToList();
return new Difference<T>
{
ChangedProperties = differences,
NewItem = newItem,
OldItem = oldItem
};
}
AreEqual just compares the serialized versions of two objects using Json.Net, this keeps it from treating reference types and value types differently.
GetDifference checks the properties on the passed in objects and compares them individually.
To get a list of differences:
var oldPersonList = new List<Person> {
new Person { Name = "Bill" },
new Person { Name = "Bob" }
};
var newPersonList = new List<Person> {
new Person { Name = "Bill" },
new Person { Name = "Bobby" }
};
var diffList = oldPersonList.Zip(newPersonList, GetDifference)
.Where(d => d.ChangedProperties.Any())
.ToList();
Everyone always tries to get fancy and write these overly generic ways of extracting data. There is a cost to that.
Why not be old school simple.
Have a GetDifferences member function Person.
virtual List<String> GetDifferences(Person otherPerson){
var diffs = new List<string>();
if(this.X != otherPerson.X) diffs.add("X");
....
}
In inherited classes. Override and add their specific properties. AddRange the base function.
KISS - Keep it simple. It would take you 10 minutes of monkey work to write it, and you know it will be efficient and work.
I am doing it by using this:
//This structure represents the comparison of one member of an object to the corresponding member of another object.
public struct MemberComparison
{
public static PropertyInfo NullProperty = null; //used for ROOT properties - i dont know their name only that they are changed
public readonly MemberInfo Member; //Which member this Comparison compares
public readonly object Value1, Value2;//The values of each object's respective member
public MemberComparison(PropertyInfo member, object value1, object value2)
{
Member = member;
Value1 = value1;
Value2 = value2;
}
public override string ToString()
{
return Member.name+ ": " + Value1.ToString() + (Value1.Equals(Value2) ? " == " : " != ") + Value2.ToString();
}
}
//This method can be used to get a list of MemberComparison values that represent the fields and/or properties that differ between the two objects.
public static List<MemberComparison> ReflectiveCompare<T>(T x, T y)
{
List<MemberComparison> list = new List<MemberComparison>();//The list to be returned
if (x.GetType().IsArray)
{
Array xArray = x as Array;
Array yArray = y as Array;
if (xArray.Length != yArray.Length)
list.Add(new MemberComparison(MemberComparison.NullProperty, "array", "array"));
else
{
for (int i = 0; i < xArray.Length; i++)
{
var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
else
{
foreach (PropertyInfo m in x.GetType().GetProperties())
//Only look at fields and properties.
//This could be changed to include methods, but you'd have to get values to pass to the methods you want to compare
if (!m.PropertyType.IsArray && (m.PropertyType == typeof(String) || m.PropertyType == typeof(double) || m.PropertyType == typeof(int) || m.PropertyType == typeof(uint) || m.PropertyType == typeof(float)))
{
var xValue = m.GetValue(x, null);
var yValue = m.GetValue(y, null);
if (!object.Equals(yValue, xValue))//Add a new comparison to the list if the value of the member defined on 'x' isn't equal to the value of the member defined on 'y'.
list.Add(new MemberComparison(m, yValue, xValue));
}
else if (m.PropertyType.IsArray)
{
Array xArray = m.GetValue(x, null) as Array;
Array yArray = m.GetValue(y, null) as Array;
if (xArray.Length != yArray.Length)
list.Add(new MemberComparison(m, "array", "array"));
else
{
for (int i = 0; i < xArray.Length; i++)
{
var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
else if (m.PropertyType.IsClass)
{
var xValue = m.GetValue(x, null);
var yValue = m.GetValue(y, null);
if ((xValue == null || yValue == null) && !(yValue == null && xValue == null))
list.Add(new MemberComparison(m, xValue, yValue));
else if (!(xValue == null || yValue == null))
{
var compare = ReflectiveCompare(m.GetValue(x, null), m.GetValue(y, null));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
return list;
}
Here you have a code which does what you want with Reflection.
public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP)
{
List<Difference> allDiffs = new List<Difference>();
foreach (Person oldPerson in oldP)
{
foreach (Person newPerson in newP)
{
Difference curDiff = GetDifferencesTwoPersons(oldPerson, newPerson);
allDiffs.Add(curDiff);
}
}
return allDiffs;
}
private Difference GetDifferencesTwoPersons(Person OldPerson, Person NewPerson)
{
MemberInfo[] members = typeof(Person).GetMembers();
Difference returnDiff = new Difference();
returnDiff.NewPerson = NewPerson;
returnDiff.OldPerson = OldPerson;
returnDiff.ChangedProperties = new List<string>();
foreach (MemberInfo member in members)
{
if (member.MemberType == MemberTypes.Property)
{
if (typeof(Person).GetProperty(member.Name).GetValue(NewPerson, null).ToString() != typeof(Person).GetProperty(member.Name).GetValue(OldPerson, null).ToString())
{
returnDiff.ChangedProperties.Add(member.Name);
}
}
}
return returnDiff;
}

C# Refactoring the same action with different details using design patterns

I try to find the way for refactoring my code but no idea how to do this.
For example, we have several classes
class A {
string name;
int year;
}
class B {
long id;
string code;
DateTime currentTime;
}
class C {
string lastname;
DateTime currentDate;
}
And latter I need to return list of objects of these classes List, List, List and convert them into Object[][].
For every conversion I do the same
private Object[][] converAListToObjectArray(List<A> dataList)
{
long countRecords = dataList.Count();
const int countProperty = 2;
var arrayRes = new object[countRecords][];
for (int i = 0; i < countRecords; i++)
{
var arrayObjProperty = new object[countProperty];
arrayObjProperty[0] = dataList[i].Name;
arrayObjProperty[1] = dataList[i].Year;
arrayRes[i] = arrayObjProperty;
}
return arrayRes;
}
private Object[][] converBListToObjectArray(List<B> dataList)
{
long countRecords = dataList.Count();
const int countProperty = 3;
var arrayRes = new object[countRecords][];
for (int i = 0; i < countRecords; i++)
{
var arrayObjProperty = new object[countProperty];
arrayObjProperty[0] = dataList[i].Id;
arrayObjProperty[1] = dataList[i].Code;
arrayObjProperty[2] = dataList[i].CurrentTime;
arrayRes[i] = arrayObjProperty;
}
return arrayRes;
}
Is it possible separate this convertion using some design pattern?
You could write a generic function which uses reflection to get each object's field names and values. You'd need to decide whether it should work for public or private fields. The example below grabs both the public and the private fields:
static object[][] ConvertToObjectArray<T>(IList<T> objects)
{
var fields = (from fieldInfo in typeof(T).GetFields(
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
orderby fieldInfo.Name
select fieldInfo).ToArray();
object[][] table = new object[objects.Count][];
for (int i = 0; i < table.Length; i++)
{
table[i] = (from fieldInfo in fields
select fieldInfo.GetValue(objects[i])).ToArray();
}
return table;
}
You could use an action and do something like this: -
class Program
{
// Your new function, (doesn't have to be static; just did it for the demo)
// If you really really want to return object[][] still,
// You'll need to pass an index to foo as well
private static List<IList<object>> convert<T>(IList<T> dataList, Action<IList<object>, T> foo)
{
var arrayRes = new List<IList<object>>();
foreach (var item in dataList)
{
var arrayObjProperty = new List<object>();
foo(arrayObjProperty, item);
arrayRes.Add(arrayObjProperty);
}
return arrayRes;
}
// The rest is just calling the function with two examples
static void Main(string[] args)
{
var bar = new List<A>();
bar.Add(new A() { name = "qux", year = 2013 });
var objects1 = convert(bar, (a, b) =>
{
a.Add(b.name);
a.Add(b.year);
});
var baz = new List<B>();
baz.Add(new B() { code = "qux", id = 2013 });
var objects2 = convert(baz, (a, b) =>
{
a.Add(b.code);
a.Add(b.id);
});
}
}
You can just copy this into your IDE to have a play and see how it works. Basically, this uses generics and then an action to allow you to do the only part that differs each time in a lambda that is passed to the method.
You could simplify and use something like this - e.g. for B...
List<B> list = new List<B>
{
new B{ id = 1, code = "", currentTime = DateTime.Now},
new B{ id = 1, code = "", currentTime = DateTime.Now},
new B{ id = 1, code = "", currentTime = DateTime.Now},
};
var array = list.Select(x => new object[] { x.id, x.code, x.currentTime }).ToArray();
Your Object[][] structure is a little unusual to my eye. Did you know there's a Cast method for lists?
You can do the following:
List<A> foo = new List<A> ();
// initialize foo here
var bar = foo.Cast<Object>().ToArray();
Which will get you a an array of objects with your field names intact. If you absolutely need to have the fields as array elements (why do you want this) you could add a ToObject method to each of your classes:
class A
{
public string name;
public int year;
public Object[] ToObject()
{
return new Object[] {name, year};
}
}
List<A> foo = new List<A>
{
new A{name="reacher",year=2013},
new A{name="Ray",year=2013}
};
var bux = foo.Select(a => a.ToObject()).ToArray() ;

Calculate average in LINQ C# with string representation of property name

I need to calculate a whole bunch of averages on an List of Surveys. The surveys have lots of properties that are int and double valued. I am creating a business object to handle all the calculations (there are like 100) and I'd rather not code 100 different methods for finding the average for a particular property.
I'd like to be able to have the UI pass a string (representing the property) and have the the business object return an average for that property.
So, like...
int AverageHeightInInches = MyObject.GetIntAverage("HeightInInches");
.
.
.
Then have linq code to calculate the result.
Thanks!
I have created this little example, it uses the System.Linq.Expression namespace to create a function that can calculate averages based on the property name. The function can be cached for later use, reflection is only used to create the function, not each time the function is executed.
EDIT: I removed the existing reflection example and updated the current example to show the ability to walk a list of properties.
static class Program
{
static void Main()
{
var people = new List<Person>();
for (var i = 0; i < 1000000; i++)
{
var person = new Person { Age = i };
person.Details.Height = i;
person.Details.Name = i.ToString();
people.Add(person);
}
var averageAgeFunction = CreateIntegerAverageFunction<Person>("Age");
var averageHeightFunction = CreateIntegerAverageFunction<Person>("Details.Height");
var averageNameLengthFunction = CreateIntegerAverageFunction<Person>("Details.Name.Length");
Console.WriteLine(averageAgeFunction(people));
Console.WriteLine(averageHeightFunction(people));
Console.WriteLine(averageNameLengthFunction(people));
}
public static Func<IEnumerable<T>, double> CreateIntegerAverageFunction<T>(string property)
{
var type = typeof(T);
var properties = property.Split('.'); // Split the properties
ParameterExpression parameterExpression = Expression.Parameter(typeof(T));
Expression expression = parameterExpression;
// Iterrate over the properties creating an expression that will get the property value
for (int i = 0; i < properties.Length; i++)
{
var propertyInfo = type.GetProperty(properties[i]);
expression = Expression.Property(expression, propertyInfo); // Use the result from the previous expression as the instance to get the next property from
type = propertyInfo.PropertyType;
}
// Ensure that the last property in the sequence is an integer
if (type.Equals(typeof(int)))
{
var func = Expression.Lambda<Func<T, int>>(expression, parameterExpression).Compile();
return c => c.Average(func);
}
throw new Exception();
}
}
public class Person
{
private readonly Detials _details = new Detials();
public int Age { get; set; }
public Detials Details { get { return _details; } }
}
public class Detials
{
public int Height { get; set; }
public string Name { get; set; }
}
Here is an example to do that.
class Survey
{
public int P1 { get; set; }
}
class MyObject
{
readonly List<Survey> _listofSurveys = new List<Survey> { new Survey { P1 = 10 }, new Survey { P1 = 20 } };
public int GetIntAverage(string propertyName)
{
var type = typeof(Survey);
var property = type.GetProperty(propertyName);
return (int)_listofSurveys.Select(x => (int) property.GetValue(x,null)).Average();
}
}
static void Main(string[] args)
{
var myObject = new MyObject();
Console.WriteLine(myObject.GetIntAverage("P1"));
Console.ReadKey();
}
if you are using linq2sql i would suggest DynamicLinq
you could then just do
datacontext.Surveys.Average<double>("propertyName");
the dynamic linq project provides the string overloads to IQueryable.
You can do this without reflection (both int and double are supported):
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, int> selector)
{
return surveys.Average(selector);
}
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, double> selector)
{
return surveys.Average(selector);
}
Usage:
var average1 = surveys.Average(survey => survey.Property1);
var average2 = surveys.Average(survey => survey.Property2);

C# Reflection Indexed Properties

I am writing a Clone method using reflection. How do I detect that a property is an indexed property using reflection? For example:
public string[] Items
{
get;
set;
}
My method so far:
public static T Clone<T>(T from, List<string> propertiesToIgnore) where T : new()
{
T to = new T();
Type myType = from.GetType();
PropertyInfo[] myProperties = myType.GetProperties();
for (int i = 0; i < myProperties.Length; i++)
{
if (myProperties[i].CanWrite && !propertiesToIgnore.Contains(myProperties[i].Name))
{
myProperties[i].SetValue(to,myProperties[i].GetValue(from,null),null);
}
}
return to;
}
if (propertyInfo.GetIndexParameters().Length > 0)
{
// Property is an indexer
}
Sorry, but
public string[] Items { get; set; }
is not an indexed property, it's merely of an array type!
However the following is:
public string this[int index]
{
get { ... }
set { ... }
}
What you want is the GetIndexParameters() method. If the array that it returns has more than 0 items, that means it's an indexed property.
See the MSDN documentation for more details.
If you call property.GetValue(obj,null), and the property IS indexed, then you will get a parameter count mismatch exception. Better to check whether the property is indexed using GetIndexParameters() and then decide what to do.
Here is some code that worked for me:
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
object value = property.GetValue(obj, null);
if (value is object[])
{
....
}
}
P.S. .GetIndexParameters().Length > 0) works for the case described in this article: http://msdn.microsoft.com/en-us/library/b05d59ty.aspx
So if you care about the property named Chars for a value of type string, use that, but it does not work for most of the arrays I was interested in, including, I am pretty sure, a string array from the original question.
You can convert the indexer to IEnumerable
public static IEnumerable<T> AsEnumerable<T>(this object o) where T : class {
var list = new List<T>();
System.Reflection.PropertyInfo indexerProperty = null;
foreach (System.Reflection.PropertyInfo pi in o.GetType().GetProperties()) {
if (pi.GetIndexParameters().Length > 0) {
indexerProperty = pi;
break;
}
}
if (indexerProperty.IsNotNull()) {
var len = o.GetPropertyValue<int>("Length");
for (int i = 0; i < len; i++) {
var item = indexerProperty.GetValue(o, new object[]{i});
if (item.IsNotNull()) {
var itemObject = item as T;
if (itemObject.IsNotNull()) {
list.Add(itemObject);
}
}
}
}
return list;
}
public static bool IsNotNull(this object o) {
return o != null;
}
public static T GetPropertyValue<T>(this object source, string property) {
if (source == null)
throw new ArgumentNullException("source");
var sourceType = source.GetType();
var sourceProperties = sourceType.GetProperties();
var properties = sourceProperties
.Where(s => s.Name.Equals(property));
if (properties.Count() == 0) {
sourceProperties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
properties = sourceProperties.Where(s => s.Name.Equals(property));
}
if (properties.Count() > 0) {
var propertyValue = properties
.Select(s => s.GetValue(source, null))
.FirstOrDefault();
return propertyValue != null ? (T)propertyValue : default(T);
}
return default(T);
}

Categories