Replicating dynamic multi-dimensional array creation of PHP - c#

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

Related

Using Indexers for multiple Arrays in the class c#

I have two arrays in my Base class, and I want to create Indexers that can be used in both of them, attached below is an MVCE of what I am trying to do.
class Indexer
{
private string[] namelist = new string[size];
private char[] grades = new string[size];
static public int size = 10;
public IndexedNames() {
for (int i = 0; i < size; i++){
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
public string this[int index] {
get {
string tmp;
if( index >= 0 && index <= size-1 ) {
tmp = namelist[index];
} else {
tmp = "";
}
return ( tmp );
}
set {
if( index >= 0 && index <= size-1 ) {
namelist[index] = value;
}
}
}
In the above coed if you comment out the lines private char[] grades = new string[size]; and grades[i] = 'F'; then you can use the indexers as object_name[i] but I want to be able to access both namelist and grades by indexers.
Note : I cannot use structures to wrap them together as in my application, there size may not always be same.
Is this possible or I would need to go around with some hack.
Edit
I am looking for something like names.namelist[i] and names.grades[i], or some statements that I can access them separately. Also Indexer logic is not consistent, and even size varies in some arrays, that was skipped here to aid simplicity in MVCE.
Sorry, no-can-do.
Although Indexers can be Overloaded and can have more than one formal parameter, you can't make two variations based on the same Parameter in the same class. This is a Language Limitation (or blessing).
Indexers (C# Programming Guide)
However, this should lead you to several options.
You can just make use of C#7. Ref returns
Starting with C# 7.0, C# supports reference return values (ref
returns). A reference return value allows a method to return a
reference to a variable, rather than a value, back to a caller. The
caller can then choose to treat the returned variable as if it were
returned by value or by reference. The caller can create a new
variable that is itself a reference to the returned value, called a
ref local.
public ref string Namelist(int position)
{
if (array == null)
throw new ArgumentNullException(nameof(array));
if (position < 0 || position >= array.Length)
throw new ArgumentOutOfRangeException(nameof(position));
return ref array[position];
}
...
// Which allows you to do funky things like this, etc.
object.NameList(1) = "bob";
You could make sub/nested classes with indexers
That's to say, you could create a class that has the features you need with indexers, and make them properties of the main class. So you get something like you envisaged object.Namelist[0] and object.Grades[0].
Note : in this situation you could pass the arrays down as references and still access them in the main array like you do.
Example which includes both:
Given
public class GenericIndexer<T>
{
private T[] _array;
public GenericIndexer(T[] array)
{
_array = array;
}
public T this[int i]
{
get => _array[i];
set => _array[i] = value;
}
}
Class
public class Bobo
{
private int[] _ints = { 2, 3, 4, 5, 5 };
private string[] _strings = { "asd","asdd","sdf" };
public Bobo()
{
Strings = new GenericIndexer<string>(_strings);
Ints = new GenericIndexer<int>(_ints);
}
public GenericIndexer<string> Strings ;
public GenericIndexer<int> Ints ;
public void Test()
{
_ints[0] = 234;
}
public ref int DoInts(int pos) => ref _ints[pos];
public ref string DoStrings(int pos) => ref _strings[pos];
}
Usage:
var bobo = new Bobo();
bobo.Ints[1] = 234;
bobo.DoInts(1) = 42;
I think only a two parameter indexer can achieve what you want.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApp1
{
class MyClass
{
protected static Dictionary<string, FieldInfo[]> table = new Dictionary<string, FieldInfo[]>();
static public int size = 10;
protected char[] grades = new char[size];
public object this[string name, int index]
{
get
{
var fieldInfos = table[this.GetType().FullName];
return ((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).GetValue(index);
}
set
{
var fieldInfos = table[this.GetType().FullName];
((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).SetValue(value, index);
}
}
static void Main()
{
var names = new MyChildClass();
names[DataColumns.Grades, 1] = 'S';
names[DataColumns.NameList, 9] = "W.S";
}
}
class MyChildClass : MyClass
{
private string[] namelist = new string[size];
static MyChildClass()
{
var t = typeof(MyChildClass);
table.Add(t.FullName, t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance));
}
public MyChildClass()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
}
static class DataColumns
{
public static string NameList = "namelist";
public static string Grades = "grades";
}
}
Maybe something like this:
class Indexer
{
private string[] namelist = new string[size];
private string[] grades = new string[size + 1]; // size +1 to indicate different
// size
static public int size = 10;
public void IndexedNames()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = "F";
}
}
public string this[int i, int j]
{
get
{
string tmp;
// we need to return first array
if (i > 0)
{
tmp = namelist[i];
}
else
{
tmp = grades[i];
}
return (tmp);
}
set
{
if (i > 0)
{
namelist[i] = value;
}
else grades[i] = value;
}
}
}

C# - Representing multiple arrays as a List<Tuple<x,x,x,x,>>

We have an old framework called CAGen in which legacy mainframe devs create "CABS" and then .NET code is generated to allow consumption in more modern languages. Unfortunately it seems to take thew rows of results from the underlying database and rather than create an object with properties its "groups" are generated as multiple arrays (one per column) all of equal length along with a Length value so we know how many rows to read.
Rather than manually handle reach column I'd like to build some kind of wrapper class which takes all the arrays and exposes them as if they were a List. I'd like it to be compile safe and was thinking using Tuples. Rather than start from scratch I'm wondering if anyone knows of a neat approach or existing component that may help ease the burden?
UPDATE: Definitive answer
Thanks to Linq and some insight from a colleague it's a one liner to wrap any number of arrays onto a model for easy iteration with a foreach:
int[] ids = new int[5] { 5, 3, 2, 1, 4 };
string[] names = new string[5] { "John", "Joan", "Bob", "Mark", "Someone" };
bool[] bools = new bool[5] { true, true, false, true, false };
var items = ids.ToList().Select(
(id, index) =>
new
{
ID = id,
Name = names[index],
YesOrNo = bools[index]
});
==========================================================
Thanks for the idea Gary.
Here's what I came up with:
public class MultiListWrapper : List<object[]>
{
private Type[] fieldTypes;
public MultiListWrapper(int length, params object[] fields)
{
fieldTypes = fields.Select(f => f.GetType()).ToArray();
for (int r = 0; r < length; r++)
{
var row = new object[fields.Length];
for (int f = 0; f < fields.Length; f++)
{
var field = fields[f];
row[f] = (field as Array).GetValue(r);
}
Add(row);
}
}
}
As it is the underlying values once instantiated still do show up as type object but I'm thinking that I could still provide a property or IEnumerable< TModel > Get< TModel >() method would would use the fieldTypes array as validation / casting to the requested model for each row and perhaps rather than subclass a List, just use compostition and hold the list internally to force casting for the consumer.
At any rate, it seems like two lines of code now to wrap the multiple arrays to a nice object which can be enumerated and used like any old Enumerable POCO.
========================================
Edit:
So I've finished off the implementation, thought I'd post it here in case anyone was interested:
public class MultiListWrapper<T> : IEnumerable<T>
where T : class, new()
{
private List<object[]> list = new List<object[]>();
private Type[] fieldTypes;
private int length = 0;
public MultiListWrapper(int length, params object[] fields)
{
this.length = length;
fieldTypes = fields.Select(f => f.GetType()).ToArray();
for (int r = 0; r < length; r++)
{
var row = new object[fields.Length];
for (int f = 0; f < fields.Length; f++)
{
var field = fields[f];
row[f] = (field as Array).GetValue(r);
}
list.Add(row);
}
}
public int Count { get { return length; } }
public T this[int index]
{
get
{
if (index >= length)
throw new IndexOutOfRangeException();
// Create the return item
var item = new T();
var properties = item.GetType().GetProperties();
// Get fields from list item
var listItem = list[index];
for (int i = 0; i < listItem.Length; i++)
{
if(properties[i].PropertyType.FullName != fieldTypes[i].FullName.Replace("[]", string.Empty))
throw new SettingsPropertyWrongTypeException(
string.Format("The type for Property '{0}' on the requested model '{1}' doesn't match the underlying list item property type",
properties[i].Name,
typeof(T).FullName));
properties[i].SetValue(item, listItem[i]);
}
return item;
}
}
private MultiListWrapperEnumerator<T> _enumerator;
public IEnumerator<T> GetEnumerator()
{
if (_enumerator == default(MultiListWrapperEnumerator<T>))
{
_enumerator = new MultiListWrapperEnumerator<T>(this);
}
return _enumerator;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#region Enumerator for the wrapper
private class MultiListWrapperEnumerator<T> : IEnumerator<T>
where T : class, new()
{
private MultiListWrapper<T> _listWrapper;
private int _index;
public MultiListWrapperEnumerator(MultiListWrapper<T> listWrapper)
{
_listWrapper = listWrapper;
_index = -1;
}
public void Dispose()
{
}
public bool MoveNext()
{
_index++;
if (_index >= _listWrapper.Count)
return false;
return true;
}
public void Reset()
{
_index = -1;
}
public T Current
{
get { return _listWrapper[_index]; }
private set { throw new NotImplementedException(); }
}
object IEnumerator.Current
{
get { return Current; }
}
}
#endregion
}
To use it you create you various arrays (all the same length), create a POCO model to represent "rows" against the array elements then pass them all into the wrapper:
public class TheModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool YesOrNo { get; set; }
}
int[] ids = new int[5] { 1, 2, 3, 4, 5 };
string[] names = new string[5] { "John", "Joan", "Bob", "Mark", "Someone" };
bool[] bools = new bool[5] { true, true, false, true, false };
var wrappedList = new MultiListWrapper<TheModel>(5, ids, names, bools);
then request an element like so:
var bob = wrappedList[2];
it's enumerable as well:
foreach (var item in wrappedList)
{
Console.WriteLine("{0}\t{1}\t{2}", item.Id, item.Name, item.YesOrNo);
}
Checks are being done in the indexer to ensure the types on the array elements match the property type on the Model. Ordering is going to be important with the order of the array parameters on the constructor needing to match the order the Model elements are declared.

Splitting and ordering the class c#

I have a class like
Class Foo
{
public string info { get; set; };
public string name { get; set; }
}
Now, info is like :
id=2&pid=6
id=2&pid=6&cid=7
id=2
Now, I want to sort it based on the count of parameters (after spliting by &)
so, it should be
id=2&pid=6&cid=7
id=2&pid=6
id=2
But, I have a list of properties to a class.
The code I wrote is :
private List<Foo> FuncADesc(List<Foo> listObj)
{
Dictionary<string, int> di1 = new Dictionary<string, int>();
for (int i = 0; i < listObj.Count; i++)
{
Dictionary<string,string> diTemp = GetInfo(listObj[i].info);
if (diTemp != null)
{
di1.Add(listObj[i].info, diTemp.Count);
}
}
var list = di1.Keys.ToList();
list.Sort(); // I want to sort by Descending
for (int i = 0; i < list.Count; i++)
{
listObj[i].info = list[i];
listObj[i].name = // ??? //
}
return listObj;
}
//Gets the dictionary after splitting by '&'
private Dictionary<string, string> GetInfo(string Info)
{
Dictionary<string, string> dict1 = null;
if (!string.IsNullOrWhiteSpace(Info))
{
NameValueCollection parse1 = HttpUtility.ParseQueryString(Info);
dict1 = parse1.Cast<string>()
.Select(s => new {Key = s, Value = parse1[s]})
.ToDictionary(dictElement => dictElement.Key.ToLowerInvariant(),
dictElement => dictElement.Value.ToLowerInvariant());
}
return dict1;
}
I want to return listObj but the name and info gets exchange. Is there some easy way or can you point, where can I change ?
You should be able to use LINQ to do something as simple as this:
private List<Foo> FuncADesc(List<Foo> listObj)
{
return listObj.OrderByDescending(x => x.info.Count(c => c == '&')).ToList();
}
OrderByDescending allows you to order the items in a descending fashion. This method uses the number of & characters within the info property of each item as the sort by value.

how to declare a free length 2d array in c#

Good day,
Normally I create 2D array as follow :
string [,] arr = new string [9,4];
This is a 2D array with 9 rows and 4 columns.
I would like to ask, how to create 2D array with any length.
For example, that is not nessecary to set the row to 9, it can be any number, depends on the situation.
what about simple List<List<T>> ?
This is like a concept, you naturally can wrap up this in your custom class, so consumer of your API don't see these wiered nested declarations.
public class Matrix {
private mtx = new List<List<T>>();
public void Append(T value) {
.....
}
public void InsertAt(T value, int row, int column) {
....
}
}
For that you must be using a List<List<string>> instance. Now you can dynamically add anything you want, however this also has the disadvantage over the array format that you need to check for yourself if you have reached the maximum number of rows or columns.
This Matrix class is space (based on access pattern) and performance efficient:
class Matrix<T>
{
readonly Dictionary<int, Dictionary<int, T>> _rows = new Dictionary<int, Dictionary<int, T>>();
public T this[int i, int j]
{
get
{
var row = ExpandOrGet(j);
if (!row.ContainsKey(i)) row[i] = default(T);
UpdateSize(i, j);
return row[i];
}
set
{
ExpandOrGet(j);
_rows[j][i] = value;
UpdateSize(i, j);
}
}
void UpdateSize(int i, int j)
{
if (j > SizeRows) SizeRows = j;
if (i > SizeColums) SizeColums = i;
}
public int SizeRows { get; private set; }
public int SizeColums { get; private set; }
Dictionary<int, T> ExpandOrGet(int j)
{
Dictionary<int, T> result = null;
if (!_rows.ContainsKey(j))
{
result = new Dictionary<int, T>();
_rows[j] = result;
}
else result = _rows[j];
return result;
}
}
Although you can add further utilities to facilitate your workflow.

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);

Categories