Is it possible to build function at runtime in c#?
Say I have this method:
List<object> DoSomeWork(List<object> listOfItems, bool boolA, bool boolB)
{
var resultsList = new List<object>();
foreach (var value in listOfItems)
{
var resultOfWork = CallFunction(value);
if (boolA)
{
resultOfWork = AnotherFunctionCall(resultOfWork);
}
if (boolB)
{
resultOfWork = ThirdFunctionCall(resultOfWork);
}
resultsList.Add(resultOfWork);
}
return resultsList;
}
Is there a way I can dynamically build a function at runtime to prevent the need to check boolA and boolB for every iteration of the loop?
In my head I'd have something that looks like this:
List<object> DoSomeWork(List<object> listOfItems, bool boolA, bool boolB)
{
Func<object, object> processor = (toProcess) =>
{
var resultOfWork = CallFunction(toProcess);
}
if (boolA)
{
processor += { resultOfWork = AnotherFunctionCall(resultOfWork); };
}
if (boolB)
{
processor += { resultOfWork = ThirdFunctionCall(resultOfWork); };
}
processor += { return resultOfWork; };
var resultsList = new List<object>();
foreach (var value in listOfItems)
{
resultsList.Add(processor(value));
}
return resultsList;
}
Thanks in advance.
There are several ways of achieving what you wish to achieve. You can use Linq.Expression to construct a function at run-time. However, since you've got only two Boolean flags, you can take a simpler approach that uses four "pre-built" function objects, like this:
Func<object,object> processor;
if (boolA && boolB) {
processor = v => ThirdFunctionCall(AnotherFunctionCall(CallFunction(x)));
} else if (boolA && !boolB) {
processor = v => AnotherFunctionCall(CallFunction(x));
} else if (!boolA && boolB) {
processor = v => ThirdFunctionCall(CallFunction(x));
} else {
processor = v => CallFunction(v);
}
var resultsList = listOfItems.Select(processor).ToList();
The bulk of the logic is in the chain of if conditionals, which enumerate all four possibilities for the pair {boolA, boolB}, and assigns the processor functor a lambda expression with the appropriate functionality.
Please note the absence of the explicit foreach loop, which can be replaced now with a LINQ call of Select(...) followed by ToList().
(Updated)
This example builds and compiles a function that varies based on the results you passed in.
public static object CallFunction(object item) { return item; }
public static object AnotherFunctionCall(object item) { return item; }
public static object ThirdFunctionCall(object item) { return item; }
public static MethodInfo CallFunctionMethodInfo = typeof(BuildFunction).GetMethod("CallFunction");
public static MethodInfo AnotherFunctionCallMethodInfo = typeof(BuildFunction).GetMethod("AnotherFunctionCall");
public static MethodInfo ThirdFunctionCallMethodInfo = typeof(BuildFunction).GetMethod("ThirdFunctionCall");
public static Func<object, object> CreateFunc(bool boolA, bool boolB)
{
var objectParameter = Expression.Parameter(typeof(object));
var returnVar = Expression.Variable(typeof(object), "returnVar");
var commands = new List<Expression>();
commands.Add(
Expression.Assign(
returnVar,
Expression.Call(CallFunctionMethodInfo, objectParameter)));
if (boolA)
{
commands.Add(
Expression.Assign(
returnVar,
Expression.Call(AnotherFunctionCallMethodInfo, returnVar)));
}
if (boolB)
{
commands.Add(
Expression.Assign(
returnVar,
Expression.Call(ThirdFunctionCallMethodInfo, returnVar)));
}
commands.Add(returnVar);
var body = Expression.Block(new[] { returnVar }, commands);
return Expression.Lambda<Func<object, object>>(body, objectParameter).Compile();
}
Call this function from your code Func<object, object> processor = CreateFunc(boolA,boolB);
Related
I found this interesting article Reflection Performance - Create Delegate (Properties C#)
the described approach works great for properties. So I tried to to make it work for Methods, too, but without success.
Classes / Properties / Methods
public class bmecatContent
{
private bmecatHeader header;
private bmecatCatalog catalog;
private List<bmecatFieldValue> fieldValueList;
public bmecatContent()
{
header = new bmecatHeader();
catalog = new bmecatCatalog();
}
public string DeclarationVersion { get; set; }
public string DeclarationEncoding { get; set; }
public string BmecatVersion { get; set; }
public bmecatHeader Header
{ get { return header; } }
public bmecatCatalog Catalog
{ get { return catalog; } }
}
public class bmecatCatalog
{
private List<bmecatCatalogGroupSystem> catalogGroupSystem;
private List<bmecatClassificationSystem> classificationSystem;
private List<bmecatProduct> products;
private List<bmecatProductToCataloggroupMap> productToCataloggroupMap;
public bmecatCatalog()
{
catalogGroupSystem = new List<bmecatCatalogGroupSystem>();
classificationSystem = new List<bmecatClassificationSystem>();
products = new List<bmecatProduct>();
productToCataloggroupMap = new List<bmecatProductToCataloggroupMap>();
}
public List<bmecatClassificationSystem> Classification_System
{ get { return classificationSystem; } }
public List<bmecatCatalogGroupSystem> Catalog_Group_System
{ get { return catalogGroupSystem; } }
public List<bmecatProduct> Products
{ get { return products; } }
public List<bmecatProductToCataloggroupMap> Product_To_Cataloggroup_Map
{ get { return productToCataloggroupMap; } }
public bmecatProduct GetProductByInernationalPid(string Pid)
{
// linq
var query = from prodItem in products
from innerList in prodItem.Product_Details.International_PID
where innerList.PID == Pid
select prodItem;
return query.FirstOrDefault();
}
}
my current Approach looks like:
// Properties
public static Func<object, object> BuildGetAccessor(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);
return expr.Compile();
}
// Methods (with string Parameter)
public static Func<object, string, object> BuildMethodAccessor(MethodInfo method)
{
var obj = Expression.Parameter(typeof(object), "o");
var strParam = Expression.Parameter(typeof(string), "strParam");
//var param = method.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).FirstOrDefault();
var param = Expression.Convert(strParam, method.GetParameters().First().ParameterType);
Expression<Func<object, string, object>> expr =
Expression.Lambda<Func<object, string, object>>(
Expression.Convert(Expression.Call(Expression.Convert(obj, method.DeclaringType), method, param),
typeof(object)),
obj);
return expr.Compile();
}
this code generates messages, that for the lambda-declaration a wrong number of Parameters was used.
thx a lot for your help!
// Update
this is my "work in progress" part when it Comes to creating & using the delegates:
bmecatParser parser = new bmecatParser();
// parser contains Property BmecatContent of type bmecatContent
// BmecatContent contains all properties and Methods I Need to Access at runtime
// e.g. BmecatContent.Catalog, BmecatContent.Catalog.GetProductByInernationalPid(string Pid)
// gets instance of main-class
var property = parser.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "BmecatContent");
var access = Extensions.BuildGetAccessor(property.GetGetMethod());
var resultBmecatContent = access(parser);
// gets instance of class that holds method
property = resultBmecatContent.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "Catalog");
access = Extensions.BuildGetAccessor(property.GetGetMethod());
var resultCatalog = access(resultBmecatContent);
// here I try to get value from method that has 1 Parameter (string)
var method = resultCatalog.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Single(obj => obj.Name == "GetProductByInernationalPid");
var accessProd = Extensions.BuildMethodAccessor(method);
var resultProduct = accessProd(resultCatalog, "4317784548366");
the idea behind this is to parse given classes + properties structure, where user provides propertynames / methodnames within mappinginstructions.
I'm attempting to write a simple generic cache but running into problems with generating unique enough keys with using System.Func as a callback.
What I ideally want is to be able to pass in an invocable delegate of some description so that the cache itself can get the value, and determine a key all from the same expression. Right now I'm getting exceptions because I'm not passing in an argument that implements or inherits from MethodCallExpression. What should I be using instead of a System.Func for this intended behaviour?
public class SimpleCacheKeyGenerator : ICacheKey
{
public string GetCacheKey<T>(Expression<Func<T>> action)
{
var body = (MethodCallExpression) action.Body; //!!! Exception Raised - action.Body is FieldExpression
ICollection<object> parameters = (from MemberExpression expression in body.Arguments
select
((FieldInfo) expression.Member).GetValue(
((ConstantExpression) expression.Expression).Value)).ToList();
var sb = new StringBuilder(100);
sb.Append(body.Type.Namespace);
sb.Append("-");
sb.Append(body.Method.Name);
parameters.ToList().ForEach(x =>
{
sb.Append("-");
sb.Append(x);
});
return sb.ToString();
}
}
public class InMemoryCache : ICacheService
{
private readonly ICachePolicy _cachePolicy;
private readonly ICacheKey _cacheKey;
public InMemoryCache(ICachePolicy cachePolicy, ICacheKey cacheKey)
{
_cachePolicy = cachePolicy;
_cacheKey = cacheKey;
}
public T Get<T>(Func<T> getItemCallback) where T : class
{
var cacheID = _cacheKey.GetCacheKey(() => getItemCallback);
var item = HttpRuntime.Cache.Get(cacheID) as T;
if (item == null)
{
item = getItemCallback();
if (_cachePolicy.RenewLeaseOnAccess)
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, System.Web.Caching.Cache.NoAbsoluteExpiration, _cachePolicy.ExpiresAfter);
}
else
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, DateTime.UtcNow + _cachePolicy.ExpiresAfter, System.Web.Caching.Cache.NoSlidingExpiration);
}
}
return item;
}
}
The problem is, you can't easily use both the Expression> and Func representing the same thing without duplicating the code.
You could possibly convert Expression> to a Func with LambdaExpression>.Compile() method, but that could create a performance problem, since Compile actually uses assembly emit, which is quite expensive.
Here is how i would implement the same thing without using Expressions and compilation.
You can find the same pattern everywhere in the standard Linq extensions.
Pass your argument as a separate object.
The type you use as an argument will be used for type inference for the delegate, and the argument itself will provide the arguments for the delegate at the same type.
Note that the cache in this implementation works because of the default ToString implementation of the anonimous objects used as arguments.
void Main()
{
var computeCount = 0;
var item1 = GetCached(new{x = 1, y = 2}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item1);
var item2 = GetCached(new{x = 1, y = 2}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item2);
var item3 = GetCached(new{x = 1, y = 3}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item3);
Console.WriteLine("Compute count:");
Console.WriteLine(computeCount);
}
Dictionary<string, object> _cache = new Dictionary<string, object>();
E GetCached<T, E>(T arg, Func<T,E> getter)
{
// Creating the cache key.
// Assuming T implements ToString correctly for cache to work.
var cacheKey = arg.ToString();
object result;
if (!_cache.TryGetValue(cacheKey, out result))
{
var newItem = getter(arg);
_cache.Add(cacheKey, newItem);
return newItem;
}
else
{
Console.WriteLine("Cache hit: {0}", cacheKey);
}
return (E)result;
}
Console output:
3
Cache hit: { x = 1, y = 2 }
3
4
Compute count:
2
You get this exception because (() => getItemCallback) means (() => { return getItemCallback; })
That's why action.Body is not a method call, it is the return statement. If you change your code to (() => getItemCallback()) you should not have the error. But you won't have any arguments.
To obtain arguments of the base call, you will have to change your code to accept an Expression and Compile your lambda.
public T Get<T>(Expression<Func<T>> getItemCallbackExpression) where T : class
{
var cacheID = _cacheKey.GetCacheKey(getItemCallbackExpression);
var item = HttpRuntime.Cache.Get(cacheID) as T;
if (item == null)
{
item = getItemCallback.Compile()();
if (_cachePolicy.RenewLeaseOnAccess)
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, System.Web.Caching.Cache.NoAbsoluteExpiration, _cachePolicy.ExpiresAfter);
}
else
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, DateTime.UtcNow + _cachePolicy.ExpiresAfter, System.Web.Caching.Cache.NoSlidingExpiration);
}
}
return item;
}
I won't recommend this approach because compiling an expression takes time.
It may be easier and more performant to manually generate cache keys. If you really want to automatically manage cache keys. You may have a look to Aspect Oriented Programmation using castle.Core or PostSharp. Theses tools will allow you to automatically add code to some of your methods and automatically add cache logic.
I modified the code as below, I got the expected result this way, so you can try this, I hope this would be helpful.
public class SimpleCacheKeyGenerator
{
public string GetCacheKey<T, TObject>(Expression<Func<T, TObject>> action)
{
var body = (MethodCallExpression) action.Body;
ICollection<object> parameters = body.Arguments.Select(x => ((ConstantExpression) x).Value).ToList();
var sb = new StringBuilder(100);
sb.Append(body.Type.Namespace);
sb.Append("-");
sb.Append(body.Method.Name);
parameters.ToList().ForEach(x =>
{
sb.Append("-");
sb.Append(x);
});
return sb.ToString();
}
}
public class InMemoryCache
{
public void Get<T, TObject>(Expression<Func<T, TObject>> getItemCallback)
{
var generator = new SimpleCacheKeyGenerator();
Console.WriteLine(generator.GetCacheKey(getItemCallback));
}
}
main:
private static void Main(string[] args)
{
var cache = new InMemoryCache();
var tt = new SomeContextImpl();
cache.Get<SomeContextImpl, string>(x => x.Any("hello", "hi"));
Console.ReadKey();
}
somcontextimpl:
public class SomeContextImpl
{
public string Any(string parameter1, string parameter2) { return ""; }
}
I have the following class
public class MyClass
{
public bool Delete(Product product)
{
// some code.
}
}
Now I have a helper class that looks like this
public class Helper<T, TResult>
{
public Type Type;
public string Method;
public Type[] ArgTypes;
public object[] ArgValues;
public Helper(Expression<Func<T, TResult>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
this.Type = typeof(T);
this.Method = body.Method.Name;
this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray();
this.ArgValues = ???
}
}
The idea ist to use this code from somewhere:
// I am returning a helper somewhere
public Helper<T> GetMethod<T>()
{
var product = GetProduct(1);
return new Helper<MyClass>(x => x.Delete(product));
}
// some other class decides, when to execute the helper
// Invoker already exists and is responsible for executing the method
// that is the main reason I don't just comile and execute my Expression
public bool ExecuteMethod<T>(Helper<T> helper)
{
var instance = new MyClass();
var Invoker = new Invoker(helper.Type, helper.Method, helper.ArgTypes, helper.ArgValues);
return (bool)Invoker.Invoke(instance);
}
The point where I am stuck is how to extract the arguments from the expression itself.
I found this way
((ConstantExpression)((MemberExpression)body.Arguments[0]).Expression).Value
which seems to be an object type with a field "product" but I believe there must be a simpler solution.
Any suggestions.
Update
Just to clarify, I modified my code according to what I want to achive. In my real word application I already have a class that does the same but without an expression tree:
var helper = new Helper(typeof(MyClass), "Delete",
new Type[] { typeof(Product) }, new object[] {product}));
The main reason for my Helper<T> is to have Compile-Time checking if the method signature is valid.
Update 2
This is my current implementation, is there a better way to acces the values, without using reflection?
public Helper(Expression<Func<T, TResult>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
this.Type = typeof(T);
this.Method = body.Method.Name;
this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray();
var values = new List<object>();
foreach(var arg in body.Arguments)
{
values.Add(
(((ConstantExpression)exp.Expression).Value).GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.Expression).Value);
);
}
this.ArgValues = values.ToArray();
}
This method works pretty well. It returns the argument types and values for an Expression>
private static KeyValuePair<Type, object>[] ResolveArgs<T>(Expression<Func<T, object>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
var values = new List<KeyValuePair<Type, object>>();
foreach (var argument in body.Arguments)
{
var exp = ResolveMemberExpression(argument);
var type = argument.Type;
var value = GetValue(exp);
values.Add(new KeyValuePair<Type, object>(type, value));
}
return values.ToArray();
}
public static MemberExpression ResolveMemberExpression(Expression expression)
{
if (expression is MemberExpression)
{
return (MemberExpression)expression;
}
else if (expression is UnaryExpression)
{
// if casting is involved, Expression is not x => x.FieldName but x => Convert(x.Fieldname)
return (MemberExpression)((UnaryExpression)expression).Operand;
}
else
{
throw new NotSupportedException(expression.ToString());
}
}
private static object GetValue(MemberExpression exp)
{
// expression is ConstantExpression or FieldExpression
if (exp.Expression is ConstantExpression)
{
return (((ConstantExpression)exp.Expression).Value)
.GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.Expression).Value);
}
else if (exp.Expression is MemberExpression)
{
return GetValue((MemberExpression)exp.Expression);
}
else
{
throw new NotImplementedException();
}
}
You can compile the argument expression and then invoke it to calculate the value:
var values = new List<object>();
foreach(var arg in body.Arguments)
{
var value = Expression.Lambda(argument).Compile().DynamicInvoke();
values.Add(value);
}
this.ArgValues = values.ToArray();
Here is an example of creation of a delegate using a lambda. The object instance is encapsulated into the delegate using a C# feature called closure.
MyClass instance = new MyClass();
//This following line cannot be changed to var declaration
//since C# can't infer the type.
Func<Product, bool> deleteDelegate = p => instance.Delete(p);
Product product = new Product();
bool deleted = deleteDelegate(product);
Alternatively you are trying to create a Helper that automagically Currys.
public class Helper<T>
where T : new()
{
public TResult Execute<TResult>(Func<T, TResult> methodLambda)
{
var instance = new T();
return methodLamda(instance);
}
}
public void Main()
{
var helper = new Helper<MyClass>();
var product = new Product();
helper.Execute(x => x.Delete(product));
}
However I have to say this problem looks suspiciously like the creation of a Helper class to handle the lifetime of a WCF proxy....You know...just say...in which case this ISN'T how I would approach this...simply because this approach leaks WCF specific code into your domain.
I have a method that uses loops through 7,753+ objects and Gets the value of each property for each object. Each object has 14 properties.
private void InitializeData(IList objects, PropertyInfo[] props, List<DPV> dataPs, List<Dictionary<string, object>> tod)
{
foreach (var item in objects)
{
var kvp = new Dictionary<string, object>();
foreach (var p in props)
{
var dataPs = dataPs.FirstOrDefault(x => x.Name == p.Name);
object returnData;
if (dataPoint != null)
{
int maxLength = (dataP.MaxLength == null) ? 0 : (int) dataP.MaxLength;
returnData = p.GetValue(item, null);
if (!string.IsNullOrEmpty(dataP.FormatString) && !string.IsNullOrEmpty(returnData.ToString()))
{
returnData = FormatDataForDisplay(returnData, dataP, maxLength, "", 8);
}
}
else
{
returnData = p.GetValue(item, null);
}
kvp.Add(p.Name, returnData);
}
tod.Add(kvp);
}
}
I believe GetValue is what takes the majority of the time in this method, The method took around 900ms to run, but GetValue which is called 800,000+ times takes around 750ms (total, not per-call).
public List<Dictionary<string, object>> GetColumnOptions<T>(List<T> list)
{
var tod= new List<Dictionary<string, object>>();
var objects = (IList)list[0];
Type objType = objects[0].GetType();
var props = objType.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
var dPs= GetDPs();
//Initialize aaData
//I don't believe this is correct
InitializeData2<T>(new List<T> { (T) objects}, props, dPs, tod);
return tod;
}
For your value class you can create direct setter and getter lambda.
The performance is nearly as fast as directly accessing the properies.
Get Setter from PropertyInfo
var propertyInfo = typeof(MyType).GetProperty("MyPropertValue");
var propertySetter = FastInvoke.BuildUntypedSetter<T>(propertyInfo));
var fieldInfo = typeof(MyType).GetField("MyFieldValue");
var fieldSetter = FastInvoke.BuildUntypedSetter<T>(fieldInfo));
Usage in a loop
var myTarget = new MyType();
setter(myTarget, aNewValue)
Helper to retrieving fast Setter an Getter
public static class FastInvoke {
public static Func<T, object> BuildUntypedGetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo); // t.PropertyName
var exConvertToObject = Expression.Convert(exMemberAccess, typeof(object)); // Convert(t.PropertyName, typeof(object))
var lambda = Expression.Lambda<Func<T, object>>(exConvertToObject, exInstance);
var action = lambda.Compile();
return action;
}
public static Action<T, object> BuildUntypedSetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo);
// t.PropertValue(Convert(p))
var exValue = Expression.Parameter(typeof(object), "p");
var exConvertedValue = Expression.Convert(exValue, GetUnderlyingType(memberInfo));
var exBody = Expression.Assign(exMemberAccess, exConvertedValue);
var lambda = Expression.Lambda<Action<T, object>>(exBody, exInstance, exValue);
var action = lambda.Compile();
return action;
}
private static Type GetUnderlyingType(this MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
default:
throw new ArgumentException
(
"Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo"
);
}
}
}
============= Performance Analysis Added ===================
5 Mio Objects, 20 Properties
3.4s direct Property access
130.0s via PropertyInfo.SetValue
4.0s via TypedSetter (code shown in article)
9.8s via UnTypedSetter (code above)
The trick is to generate the property-setter and -getter once for each class an reuse them.
// Create an fill objects fast from DataReader
// http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
static List<T> CreateObjectFromReader<T>(IDataReader reader)
where T : new()
{
// Prepare
List<string> fieldNames = GetFieldNames(reader);
List<Action<T, object>> setterList = new List<Action<T, object>>();
// Create Property-Setter and store it in an array
foreach (var field in fieldNames)
{
var propertyInfo = typeof(T).GetProperty(field);
setterList.Add(FastInvoke.BuildUntypedSetter<T>(propertyInfo));
}
Action<T, object>[] setterArray = setterList.ToArray();
// generate and fill objects
while (reader.Read())
{
T xclass = new T();
int fieldNumber = 0;
for (int i = 0; i< setterArray.Length; i++)
{
// call setter
setterArray[i](xclass, reader.GetValue(i));
fieldNumber++;
}
result.Add(xclass);
}
}
My original article (german text and older code) was https://web.archive.org/web/20141020092917/http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
If the problem is really in PropertyInfo.GetValue method call you can use the approach with building property-getters cache (for example via compiled expressions).
Here is the sample that demostrates that this approach is up to 30-40% faster than original method on 8000 objects with 14 properties (with hot cache):
static void Main(string[] args) {
IList objects = new List<Obj>();
for(int i = 0; i < 8000; i++)
objects.Add(new Obj());
var properties = typeof(Obj).GetProperties();
var sw1 = System.Diagnostics.Stopwatch.StartNew();
InitializeData1(objects, properties, new List<Dictionary<string, object>>());
sw1.Stop();
Console.WriteLine("Reflection PropertyInfo.GetValue: " + sw1.ElapsedTicks.ToString());
// cold cache testing
var sw2_coldCache = System.Diagnostics.Stopwatch.StartNew();
InitializeData2<Obj>(objects, properties, new List<Dictionary<string, object>>(), new Dictionary<string, Func<Obj, object>>());
sw2_coldCache.Stop();
Console.WriteLine("Cached Getters (Cold cache): " + sw2_coldCache.ElapsedTicks.ToString());
// cache initialization
InitializeData2<Obj>(new List<Obj> { new Obj() }, properties, new List<Dictionary<string, object>>(), gettersCache);
// hot cache testing
var sw2_hotCache = System.Diagnostics.Stopwatch.StartNew();
InitializeData2<Obj>(objects, properties, new List<Dictionary<string, object>>(), gettersCache);
sw2_hotCache.Stop();
Console.WriteLine("Cached Getters (Hot cache): " + sw2_hotCache.ElapsedTicks.ToString());
var sw3 = System.Diagnostics.Stopwatch.StartNew();
InitializeData3(objects, properties, new List<Dictionary<string, object>>());
sw3.Stop();
Console.WriteLine("returnProps special method: " + sw3.ElapsedTicks.ToString());
var sw4 = System.Diagnostics.Stopwatch.StartNew();
InitializeData2_NonGeneric(objects, properties, new List<Dictionary<string, object>>());
sw4.Stop();
Console.WriteLine("Cached Getters (runtime types resolving): " + sw4.ElapsedTicks.ToString());
}
Here is the original implementation (reduced for test purposes):
static void InitializeData1(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
foreach(var item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
kvp.Add(p.Name, p.GetValue(item, null));
}
tod.Add(kvp);
}
}
Here is the optimized implementation:
static IDictionary<string, Func<Obj, object>> gettersCache = new Dictionary<string, Func<Obj, object>>();
static void InitializeData2<T>(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod, IDictionary<string, Func<T, object>> getters) {
Func<T, object> getter;
foreach(T item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
if(!getters.TryGetValue(p.Name, out getter)) {
getter = GetValueGetter<T>(p);
getters.Add(p.Name, getter);
}
kvp.Add(p.Name, getter(item));
}
tod.Add(kvp);
}
}
static Func<T, object> GetValueGetter<T>(PropertyInfo propertyInfo) {
var instance = System.Linq.Expressions.Expression.Parameter(propertyInfo.DeclaringType, "i");
var property = System.Linq.Expressions.Expression.Property(instance, propertyInfo);
var convert = System.Linq.Expressions.Expression.TypeAs(property, typeof(object));
return (Func<T, object>)System.Linq.Expressions.Expression.Lambda(convert, instance).Compile();
}
Test class:
class Obj {
public int p00 { set; get; }
public string p01 { set; get; }
public float p02 { set; get; }
public double p03 { set; get; }
public char p04 { set; get; }
public byte p05 { set; get; }
public long p06 { set; get; }
public int p07 { set; get; }
public string p08 { set; get; }
public float p09 { set; get; }
public double p10 { set; get; }
public char p11 { set; get; }
public byte p12 { set; get; }
public long p13 { set; get; }
}
Update: Added solution from varocarbas into tests
static void InitializeData3(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
foreach(Obj item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
kvp.Add(p.Name, returnProps(p.Name, item));
}
tod.Add(kvp);
}
}
static object returnProps(string propName, Obj curObject) {
if(propName == "p00") {
return curObject.p00;
}
else if(propName == "p01") {
return curObject.p01;
}
else if(propName == "p02") {
return curObject.p02;
}
else if(propName == "p03") {
return curObject.p03;
}
else if(propName == "p04") {
return curObject.p04;
}
else if(propName == "p05") {
return curObject.p05;
}
else if(propName == "p06") {
return curObject.p06;
}
else if(propName == "p07") {
return curObject.p07;
}
else if(propName == "p08") {
return curObject.p08;
}
else if(propName == "p09") {
return curObject.p09;
}
else if(propName == "p10") {
return curObject.p10;
}
else if(propName == "p11") {
return curObject.p11;
}
else if(propName == "p12") {
return curObject.p12;
}
else if(propName == "p13") {
return curObject.p13;
}
return new object();
}
Console Results: (Release, x64) (Core i5 M560 #2.67 GHz, 8GB RAM, Win7x64)
Reflection PropertyInfo.GetValue: 161288
Cached Getters (Cold cache): 153808
Cached Getters (Hot cache): 110837
returnProps special method: 128905
Thus, the caching approach is the best.
UPDATE2
The methods demonstrated in sample are intended to be used when the type of objects elements is known at compile time (generic way):
InitializeData2<Obj>(...)
If you are using the objects list which type is unknown at compile-time, you can use the following approach to invoke the InitializeData2<> generic method at run-time:
InitializeData2_NonGeneric(objects, properties, new List<Dictionary<string, object>>());
//...
static void InitializeData2_NonGeneric(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
Type elementType = objects[0].GetType();
var genericMethodInfo = typeof(Program).GetMethod("InitializeData2", BindingFlags.Static | BindingFlags.NonPublic);
var genericMethod = genericMethodInfo.MakeGenericMethod(new Type[] { elementType });
var genericGetterType = typeof(Func<,>).MakeGenericType(elementType,typeof(object));
var genericCacheType = typeof(Dictionary<,>).MakeGenericType(typeof(string), genericGetterType);
var genericCacheConstructor = genericCacheType.GetConstructor(new Type[] { });
genericMethod.Invoke(null, new object[] { objects, props, tod, genericCacheConstructor.Invoke(new object[] { }) });
}
I did a simple test where I replaced the problematic .GetValue with a function performing a simplistic assignation ("if the name of the property is blabla, the value is Object.blabla"). The test consists just in a simple version of your function/variable/properties and a loop allowing to have full control over the number of iterations. The results have been certainly surprising: the new approach is 10 times faster! Bear in mind that in my original tests (50000 iterations) the times were 2276 (old) vs. 234 (new). This difference remains constant for different scenarios; for example for 8000 iterations, it delivers 358ms vs. 36ms. I have done these tests on a pretty powerful computer and on C# winforms; #Xaisoft can take the code below, perform a test under his specific conditions and tell the results.
The code:
private void Form1_Load(object sender, EventArgs e)
{
List<List> var = new List<List>();
List var1 = new List();
var1.var = 1;
var1.var2 = 1;
var1.var3 = 1;
var1.var4 = 1;
var1.var5 = 1;
List var2 = new List();
var2.var = 1;
var2.var2 = 1;
var2.var3 = 1;
var2.var4 = 1;
var2.var5 = 1;
List var3 = new List();
var3.var = 1;
var3.var2 = 1;
var3.var3 = 1;
var3.var4 = 1;
var3.var5 = 1;
List var4 = new List();
var4.var = 1;
var4.var2 = 1;
var4.var3 = 1;
var4.var4 = 1;
var4.var5 = 1;
var.Add(var1);
var.Add(var2);
var.Add(var3);
var.Add(var4);
InitializeData(var, typeof(List).GetProperties());
}
private static void InitializeData(List<List> objects, PropertyInfo[] props)
{
DateTime start = DateTime.Now;
int count = 0;
do
{
count = count + 1;
foreach (var item in objects)
{
foreach (var p in props)
{
object returnData = p.GetValue(item, null); //returnProps(p.Name, item);
}
}
} while (count < 50000);
TimeSpan timer = new TimeSpan();
timer = DateTime.Now.Subtract(start);
}
private class List
{
public int var { set; get; }
public int var2 { set; get; }
public int var3 { set; get; }
public int var4 { set; get; }
public int var5 { set; get; }
public int var6 { set; get; }
public int var7 { set; get; }
public int var8 { set; get; }
public int var9 { set; get; }
public int var10 { set; get; }
public int var11 { set; get; }
public int var12 { set; get; }
public int var13 { set; get; }
public int var14 { set; get; }
}
private static object returnProps(string propName, List curObject)
{
if (propName == "var")
{
return curObject.var;
}
else if (propName == "var2")
{
return curObject.var2;
}
else if (propName == "var3")
{
return curObject.var3;
}
else if (propName == "var4")
{
return curObject.var4;
}
else if (propName == "var5")
{
return curObject.var5;
}
else if (propName == "var6")
{
return curObject.var6;
}
else if (propName == "var7")
{
return curObject.var7;
}
else if (propName == "var8")
{
return curObject.var8;
}
else if (propName == "var9")
{
return curObject.var9;
}
else if (propName == "var10")
{
return curObject.var10;
}
else if (propName == "var11")
{
return curObject.var11;
}
else if (propName == "var12")
{
return curObject.var12;
}
else if (propName == "var13")
{
return curObject.var13;
}
else if (propName == "var14")
{
return curObject.var14;
}
return new object();
}
FINAL NOTE: I would like people to understand so impressive results more generically than just applied to .GetValue. Nowadays computers can deal with lots of things and you don't really need to maximise the performance of each single bit, this is true. On the other hand, if you have performance problems and you need to "save resources" in a more relevant way, you should focus your improvements on the idea "the simpler, the quicker". I have done myself performance improvements in codes using a relevant number of Lists and Dictionaries and the results are noticiable even after each single change (List into conventional Array). You don't need to be too alarmist on this front but, in case of being required, remember that the memory consumption/associated time requirements to a List with respect to an Array are higher (and both elements do basically the same). Same thing for multi-dimension arrays, long-sized arrays, etc.
------ MORE DETAILED PERFORMANCE ANALYSIS
Even though I have let my point very clear since the start (just an idea which has to be adapted to each situation), I do understand that my claim (10 times faster) do require a proper definition. I have been doing tests under different conditions and here come the results:
NOTE: the aforementioned results were output by a 32-bit executable; all the ones below come from a 64-bit one. I have observed an improvement on the .GetValue performance when moving from 32-bit to 64-bit. The updated 64-bit version of the results above are (ms):
GetValue Direct Assignation
50000 iterations -> 1197 157
80000 iterations -> 1922 253
100000 iterations -> 2354 310
Thus, the ratio changes from 10 times to 7.5 times.
I started increasing the number of properties (every time on 64-bit) and GetValue became better and better. Results:
28 Properties
GetValue Direct Assignation
50000 iterations -> 2386 552
80000 iterations -> 3857 872
Aver. ratio = 4.37
50 Properties
GetValue Direct Assignation
50000 iterations -> 4292 1707
80000 iterations -> 6772 2711
Aver. ratio = 2.475
I am not sure if the improvement of GetValue will continue and will reach a point where will be better than the simplistic approach but who cares? At this point, it is clear that the increasing number of properties plays against the simplistic approach, so it is time to try a different (again pretty simplistic) alternative: global array storing all the properties.
private static int[,] List0;
Being populated in parallel with the given property (i.e., when object.propX = any value the corresponding positions in the array are also populated) and referred by objects/properties positions (first object, third property, etc.). Logically, this has the limitation of the number of objects (growing the first dimension above 1000 does not sound recommendable), but you might rely on different arrays (one storing from the first object to the 1000th one, other from the 1001th to the 2000th, etc.); you can set a function taking as argument the object name and returning the corresponding array.
Modifications in the main loop:
int countObject = -1;
foreach (var item in objects)
{
countObject = countObject + 1;
int countProp = -1;
foreach (var p in props)
{
countProp = countProp + 1;
object returnData = List0[countObject, countProp];
}
}
By running this new approach in the case above, I get:
50 Properties
GetValue 2D Array
80000 iterations -> 6772 155
Aver. ratio = 45.146
One more:
70 Properties
GetValue 2D Array
80000 iterations -> 10444 213
Aver. ratio = 49.06
And I stopped my tests here. I guess that it is more than enough to prove my point.
Different approaches deliver different performances under different conditions and thus the best way to know the ideal configuration for a situation is actually testing it. Relying on an ultimate truth is rarely the best solution for a problem (although I might be wrong... still waiting for the reply from DmitryG to test his solution under different conditions). Thus, UNDER THE TESTED CONDITIONS, it seems to be the case that the original simplistic approach is acceptable for cases where the number of properties is relatively low (i.e., below 20); above this, the required hardcoding effort does not seem to be worthy and relying on a different alternative (like the 2D array I proposed) is better. In any case, GetValue delivers clearly a bad performance, which might be improved in many different ways.
I hope that I will not need to update this answer again :)
Continued from post above:
Your code builds a dictionary of property name and (formatted) value.
So we need just a List as input. From T we can derive all information.
public Dictionary<string, object> ExtractParameterNameAndValue<T>(List<T> colleciton)
where T : class
{
var result = new Dictionary<string, object>();
// out of the loop - generate getters
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var getterList = new List<Func<T,object>>();
foreach (var p in properties)
{
getterList.Add(MyStatic.BuildUntypedGetter<T>(p));
}
// Array of getters
var getters = getterList.ToArray(); // improving performance (?) - never use Dictionary
// Corresponding array of Names
var names = properties.Select(p => p.Name).ToArray();
// iterate all data
int counter = 0;
foreach (var item in colleciton)
{
for (int i = 0; i< getters.Length; i++)
{
var name = names[i]; // name from property
var value = getters[i](item); // value from getter-call
result.Add(counter + " " + name, value);
}
counter++;
}
return result; ;
}
The method BuildUntypedGetter() is like
// see http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
public static Func<T, object> BuildUntypedGetter<T>(PropertyInfo propertyInfo)
{
var targetType = propertyInfo.DeclaringType;
var methodInfo = propertyInfo.GetGetMethod();
var returnType = methodInfo.ReturnType;
var exTarget = Expression.Parameter(targetType, "t");
var exBody = Expression.Call(exTarget, methodInfo);
var exBody2 = Expression.Convert(exBody, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(exBody2, exTarget);
var action = lambda.Compile();
return action;
}
There is no need to specify the type in the call. It is detected by type inference.
var accountList = new List<Account>()
{
new Account { Name = "X1", Name2 ="X2"},
new Account { Name = "X3", Name2 ="X4"},
new Account { Name = "X5", Name2 ="X6"},
};
var result = ExtractParameterNameAndValue(accountList);
I know this has been asked before, but the solutions I have tried never take into consideration nullable types.
I need something that will be able to handle a conversion like
List<string> to List<Int32?>, List<string> to List<int>, List<string>
to List<double>
etc.
I am trying to create something as follows
private void RoutineCompleted(string category, List Type fieldType = null)
{
//ToNewType is the extension method that I need.
var var convertedList = values.ToNewType(fieldType);
}
I have looked at the following code, but it does not do the job:
public static IEnumerable Cast(this IEnumerable self, Type innerType)
{
var methodInfo = typeof(Enumerable).GetMethod("Cast");
var genericMethod = methodInfo.MakeGenericMethod(innerType);
return genericMethod.Invoke(null, new object[] { self }) as IEnumerable;
}
Can anyone help me figure this out?
Thanks!
You do not need an extension if you can convert using Convert.To... methods
List<string> strList = ...
List<int> intList = strList.Select(s => Convert.ToInt32(s)).ToList();
or you can use Convert.ChangeType
public static IEnumerable<TOut> ConvertTo<TIn, TOut>(this IEnumerable<TIn> list)
{
return list.Select(o => (TOut)Convert.ChangeType(o, typeof (TOut)));
}
List<string> strList = new List<string>();
IEnumerable<int> intList = strList.ConvertTo<string, int>();
The conversions you're talking about are not casts per se, but type conversions.
You can do them using Linq, for example like this:
var ints = new List(){1,2,3,4,51};
var strings = array.Select(x => x.ToString());
or
var strings = new List() {"1.56","2.71","3.14"};
var doubles = strings.Select( x => Convert.ToDouble(x));
Those give you IEnumerables, but you can make them into Lists using .ToList().
the Convert class cannot deal with Nullable types, so I had to special-case those.
static void Main(string[] args)
{
var strings = new[] { "1","2","3"};
var ints = strings.ConvertItems<string, int>().ToList();
var doubles = strings.ConvertItems<string, double>().ToList();
var nullableints = strings.ConvertItems<string, int?>().ToList();
}
public static IEnumerable<TargetType> ConvertItems<SourceType, TargetType>(this IEnumerable<SourceType> sourceCollection)
{
var targetType = typeof(TargetType);
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
targetType = targetType.GetGenericArguments().First();
}
return sourceCollection.ConvertItems((source) => (TargetType)Convert.ChangeType(source, targetType));
}
public static IEnumerable<TargetType> ConvertItems<SourceType, TargetType>(this IEnumerable<SourceType> sourceCollection, Converter<SourceType, TargetType> convertor)
{
foreach (var item in sourceCollection)
{
yield return convertor(item);
}
}
EDIT: weakly-typed version, when you only know the type at runtime
static void Main(string[] args)
{
var strings = new[] { "1","2","3"};
var ints = strings.ConvertItems(typeof(int));
var doubles = strings.ConvertItems(typeof(double));
var nullableints = strings.ConvertItems(typeof(int?));
foreach (int? item in nullableints)
{
Console.WriteLine(item);
}
}
public static IEnumerable ConvertItems(this IEnumerable sourceCollection,Type targetType)
{
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
targetType = targetType.GetGenericArguments().First();
}
foreach (var item in sourceCollection)
{
yield return Convert.ChangeType(item, targetType);
}
}
This is a simple LINQ Select:
IEnumerable<string> values = new[] { "1", "2", "3" };
var converted = values.Select(PerformConversion);
private int? PerformConversion(string input)
{
...
}
You will need a different method for each conversion, or a parameterised method to encompassed all of them. For example:
private T? PerformConversion<T>(string input) where T : struct, IConvertible
{
return (T?) Convert.ChangeType(input, typeof(T));
}
You can try with this:
public static IEnumerable<TTo> ChangeType<TTo, TFrom>(this IEnumerable<TFrom> self)
{
return self.Select(e => (TTo)Convert.ChangeType(e, typeof(TTo)));
}
EDIT:
If you don't wan't to use generic's and you have to pass type: Type like this:
var list = new List<string> {"1", "3", "4", null};
var result = list.ChangeType(typeof (int?));
You can try use this:
public static IEnumerable ChangeType(this IEnumerable self, Type type)
{
var converter = TypeDescriptor.GetConverter(type);
foreach (var obj in self)
{
yield return converter.ConvertFrom(obj);
}
}