How to use linq functions like Sum() with dynamic variable - c#

Type t = Type.GetType(obj.ToString());
PropertyInfo p = t.GetProperty("Test");
dynamic kk = p.GetValue(obj, null);
In this, Test is an int List. I need to get the sum of all the values from int list ie., kk.

var list = p.GetValue(obj, null) as IEnumerable<int>;
var result = list.Sum();

// Type t = Type.GetType(obj.ToString());
Type t = obj.GetType(); // You might be able to replace the above line with this, simpler verison.
PropertyInfo p = t.GetProperty("Test");
object kk = p.GetValue(obj, null);
int Sum = (kk as List<int>).Sum();

Related

How to call a method with instance using Expression

For example I have some class with some property:
public class SomeClass
{
public Version Version { get; set; }
}
And I have a list of this type with sample data:
var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
list.Add(new SomeClass
{
Version = new Version(i, i / 2, i / 3, i / 4),
});
}
I want to write method that filters by version using Version.Equals method:
var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
var value = Expression.Convert(Expression.Constant(filterValue), propertyType);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
/////////
Expression inst = null; // <-- ???
/////////
var expr = Expression.Call(inst, versionEqualsMethod, property, value);
var delegateType = typeof(Func<,>).MakeGenericType(modelType, typeof(bool));
var delegateValue = Expression.Lambda(delegateType, expr, arg).Compile();
var genericMethod =
typeof(Enumerable).GetMethods()
.First(
method =>
method.Name == "Where" && method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 1 && method.GetParameters().Length == 2)
.MakeGenericMethod(modelType);
var result = genericMethod.Invoke(null, new object[] { list, delegateValue });
What do I use as instance in Expression.Call?
UPDATE
Solution is:
var expr = Expression.Call(property, versionEqualsMethod, value);
You normally would do:
var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
// Changes from here onward
var value = Expression.Constant(filterValue);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
var expr = Expression.Call(property, versionEqualsMethod, value);
Because the Equals would be used like:
model.Version.Equals(filterValue);
I'm not handling the model.Version == null case!
Note that you don't need the Expression.Convert.
And what you are doing is ok if the "containing method" (the method where you'll put this code) is non-generic, but normally it would be a generic method, that has as the generic parameter the modelType, so the last part of the code would be different (starting from var delegateType =), because you could use the TModelType generic type directly.
Maybe I'm missing out on something, but wouldn't this work:
var results = list.Where(sc => sc.Version == filterVersion);
What you are trying to accomplish is much easier to do with reflection. Check this running online example. (If I understand you correctly that is... It would be helpful, if you could provide the signature of the function you are trying to write.)
Implementation
public static class Extensions
{
public static IEnumerable<T> Filter<T>(
this IEnumerable<T> enumerable, string propertyName, object filterValue)
{
var elementType = typeof (T);
var property = elementType.GetProperty(propertyName);
return enumerable.Where(element =>
{
var propertyValue = property.GetMethod.Invoke(element, new object[] {});
return propertyValue.Equals(filterValue);
});
}
}
Usage
var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
list.Add(new SomeClass {Version = new Version(i, i/2, i/3, i/4)});
}
var filteredList = list.Filter("Version", new Version(12, 6, 4, 3));
Console.WriteLine(filteredList.Single().Version);

Adapt function to included Field Names C# 2012.net 3.5

Is their anyway of changing the below to included all fields names only and values one thing i noticted that when testing this it also brought other information about the entitiy back im only wanting the fields that have been entered or changed by the user??
public static string ObjectToNotes(object obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj", "Value can not be null or Nothing!");
}
StringBuilder sb = new StringBuilder();
Type t = obj.GetType();
PropertyInfo[] pi = t.GetProperties();
for (int index = 0; index < pi.Length; index++)
{
sb.Append(pi[index].GetValue(obj, null));
if (index < pi.Length - 1)
{
sb.Append(Environment.NewLine);
}
}
return sb.ToString();
}
Right now this will save out the values for the entity only passed
As you can see from the image above the code is getting the values ok and fields but just not any drop downs related text
Help
Need more help with this how do i get the value of reference lookup values using the above method its only priting out the entity reference not the actual text value can this be done
Assuming by entered by the user you mean not having a string representation that is null or empty then try the following:
var properties = t.GetProperties();
var values = properties.Select(p => p.GetValue(obj, null)).Where(v => v != null && !string.IsNullOrEmpty(p.ToString());
var result = string.Join(Environment.NewLine, values);
In order to determine whcih fields have changed, you will need to pass two objects. One representing the entity in its pre-changed state and the other in its post-changed state and compare the properties:
var properties = t.GetProperties();
var before = properties.Select(p => new { property = p, value = p.GetValue(prechange, null) }).Where(v => v.value != null && !string.IsNullOrEmpty(p.value.ToString()).ToDictionary(p => p.property.Name, p => p.value);
var after = properties.Select(p => new { property = p, value = p.GetValue(postchange, null) }).Where(v => v.value != null && !string.IsNullOrEmpty(p.value.ToString()).ToDictionary(p => p.property.Name, p => p.value);
// You can then compare the keys / values of before and after dictionaries here

OrderBy with variable TKey

I have a list of FileInfo which I have to sort by different properties, e.g.
List<FileInfo> infoListOrdered = infoList.OrderBy(x => x.CreationTime).ToList();
Instead of writing the expression for every FileInfo property, would it be possible to pass the TKey as a parameter?
No, TKey is a type; the lamba x=>x.CreationTime is the value selector returning a value of type TKey. You can't select something based on its type only, for one there may be multiple property instances of that type in your class.
Here's a solution based on my (mis)understanding of the question. It gives OrderBy for each property prop that you might want to order by:
static void Main()
{
IEnumerable<FileInfo> infoList = XXX; // your source to sort
var orderByMeth = typeof(Enumerable).GetMethods().Single(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
var tFileInfo = typeof(FileInfo);
foreach (var prop in tFileInfo.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
{
var tKey = prop.PropertyType;
var xParam = Expression.Parameter(tFileInfo);
var propBody = Expression.Property(xParam, prop.GetMethod);
var lambda = Expression.Lambda(propBody, xParam);
var func = lambda.Compile();
var orderByMethConstr = orderByMeth.MakeGenericMethod(tFileInfo, tKey);
var result = orderByMethConstr.Invoke(null, new object[] { infoList, func, });
var infoListOrdered = (IOrderedEnumerable<FileInfo>)result;
// keep infoListOrdered; foreach through it to get that particular ordering
}
}

Why reflection does not find property

I have the class:
class Person
{
public string Name { get { return "Antonio"; } }
}
and the Code:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>( );
var observCol = uncknownObject.GetType( );
var x = ( ( dynamic )observCol ).GenericTypeArguments[ 0 ];
var y = observCol.GetProperty( "GenericTypeArguments" );
var instance = ( Person )Activator.CreateInstance( x );
Console.WriteLine( instance.Name ); // Print Antonio!!!
why does y == null ?
Note the picture:
the debugger shows that the property GenericTypeArguments should exist and the code shows the opossite. It can be proven that the debugger is right and that property exist because then how come x is not null. If that property exists then why y is equal to null!!!???
Edit
Thanks to Ani I now have:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var genTypeArgsProperty = typeof(Type).GetProperty("UnderlyingSystemType");
var genTypeArgsValue = (genTypeArgsProperty.GetValue(observCol, null));
var f = genTypeArgsValue.GetType().GetMethod("GetGenericArguments");
IEnumerable<object> result = (IEnumerable<object>)f.Invoke(genTypeArgsValue, null);
var x = result.FirstOrDefault();
var instance = Activator.CreateInstance( (Type)x );
In case of curios why I needed that functionality click here
I don't really understand what you're trying to accomplish with all this meta-meta-reflection, but you seem to have misunderstood what Type.GetProperty does. It gets meta-data for a property on the actual type represented by the System.Type instance (in this case, ObservableCollection<Person>). It does not get meta-data for a property declared on System.Type itself, unless of course you call it on a System.Type representing System.Type itself.
In your case, y is null since ObservableCollection<Person> does not have a property named "GenericTypeArguments".
Try this instead:
var genTypeArgsProperty = typeof(Type).GetProperty("GenericTypeArguments");
var genTypeArgsValue = (Type[]) (genTypeArgsProperty.GetValue(observCol, null));
var onlyTypeArgValue = genTypeArgsValue.Single();
This code works with net framework 4:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var x = ((dynamic) observCol).UnderlyingSystemType.GetGenericArguments()[0];
var y = observCol.GetGenericArguments();
var instance = (Person)Activator.CreateInstance(x);
Console.WriteLine(instance.Name); // Print Antonio!!!

C# Predicate Builder with "NOT IN" functionality

With PredicateBuilder how do I get functionality similar to the SQL IN or NOT IN query?
For example I have a list of IDs and I want to select all of the People whose IDs either Match or do not match the IDs.
The people match functionality is fairly straightforward (although there may be a better way to do it)
var predicate = PredicateBuilder.False<Person>()
foreach (int i in personIDs)
{
int temp = i;
predicate = predicate.Or(e=>e.PersonID == temp);
}
return persons.Where(predicate);
So how do I get the opposite? I want all persons whose IDs are not in the personIDs list.
Ask De Morgan:
NOT (P OR Q) = (NOT P) AND (NOT Q)
To have your code generate the equivalent of a NOT IN condition, rewrite as
var predicate = PredicateBuilder.True<Person>()
and
predicate = predicate.And(e=>e.PersonID != temp);
Do you use Entity Framework?
Then you can build the query without PredicateBuilder:
var personIds = new List<int>() { 8,9,10 };
var query = persons.Where(it => !personIds.Contains(it.PersonId));
From this LINQ statement a SQL NOT IN query is created.
Is this what you want?
var predicate = PredicateBuilder.True<Person>()
foreach (int i in personIDs)
{
int temp = i;
predicate = predicate.And(e => e.PersonID != temp);
}
return persons.Where(predicate);
Without looking at the api....
var predicate = PredicateBuilder.True<Person>()
foreach (int i in personIDs)
{
int temp = i;
predicate = predicate.And(e=>e.PersonID != temp);
}
return persons.Where(predicate);

Categories

Resources