Reflection in C#: Grouping properties and calculate sum of another properties - c#

So, I have such class:
public class PaymentsModel
{
[ReportsSummary(isGroupingSource:true)]
public string PaymentType { get; set; }
[ReportsSummary(isGroupingTarget: true)]
public double Amount { get; set; }
public string GuestName { get; set; }
}
I have List of (generic) which contains different objects with different values, for example:
{"Bank", 1, "K"},
{"Card", 2, "C"},
{"Cash", 3, "D"},
{"Bank", 2, "E"},
{"Card", 3, "G"},
I need a method CalculateSum() which will use generic class and reflection, and return Dictionary with grouping by PaymentType, and sum Amount for each PaymentType.
So result should be:
[{"Bank", 3},
{"Card", 5},
{"Cash", 5}]
I created an attribute to understand, which property should be grouped, and which - summed:
class ReportsSummaryAttribute : Attribute
{
public bool IsGroupingSource { get; private set; }
public bool IsGroupingTarget { get; private set; }
public ReportsSummaryAttribute(bool isGroupingSource = false, bool isGroupingTarget = false)
{
IsGroupingSource = isGroupingSource;
IsGroupingTarget = isGroupingTarget;
}
}
But don't understand, how to create correct method.

a possible solution you could adapt:
public class MyGenericClass<T> where T:PaymentsModel//or common baseType
{
public Dictionary<string, double> genericMethod(List<T> source)
{
var result = source.GroupBy(x => x.PaymentType)
.Select(t => new { PaymentType = t.Key, Total = t.Sum(u => u.Amount) })
.ToDictionary(t => t.PaymentType, t => t.Total);
return result;
}
}
:
:
//in processus
var myGenericClass = new MyGenericClass<PaymentsModel>();
var result = myGenericClass.genericMethod(source);

Related

Creating Dict<enum, List<objec>> from List<object> using LINQ C#

I have the following enums and class:
public enum SymbolTypeEnum
{
[Description("Forex")]
forex = 0,
[Description("Metals")]
metals = 1,
[Description("Commodities")]
commodities = 2,
[Description("Indices")]
indices = 3,
[Description("Cryptocurrency")]
cryptocurrency = 4,
[Description("Other")]
other = 5
}
public enum SymbolClassificationEnum
{
[Description("None")]
none = 0,
[Description("Major")]
major = 1,
[Description("Minor")]
minor = 2,
[Description("Exotic")]
exotic = 3
}
public class SymbolSettingsModel
{
[PrimaryKeyAttribute, Unique]
public string symbolName { get; set; }
public SymbolTypeEnum symbolType { get; set; }
public SymbolClassificationEnum symbolClassification { get; set; }
}
I have a List<SymbolSettingsModel> symbolSettings;
My goal is to generate a Dictionary<SymbolTypeEnum, List<SymbolDescr>> typeSymbolsSettingsData;
Where SymbolDescr is:
class SymbolDescr
{
public string symbol { get; set; }
public int classification { get; set; }
}
The idea is to group them by symbolType and use it as a Key for the dictionary, and generate a list of SymbolDescr. Here is my code so far:
typeSymbolsSettingsData = symbolSettings.GroupBy(p => p.symbolType)
.ToDictionary(p => p.Key, p => p.ToList());
I am stuck at this point, do you have any ideas how I can do this ?
You could use Select to project your SymbolSettingsModel instances into SymbolDescr instances:
typeSymbolsSettingsData = symbolSettings
.GroupBy(p => p.symbolType)
.ToDictionary(
p => p.Key,
p => p.Select(x => new SymbolDescr
{
symbol = x.symbolName,
classification = (int)x.symbolClassification
})
.ToList());
You should also try to comply with the .Net property naming convention which mandates the use of PascalCase.

C# Reactive Extensions (rx) FirstOrDefault enumerates entire collection

It seems that the expected behavior of FirstOrDefault is to complete after finding an item that matches the predicate and the expected behavior of concat is to evaluate lazily. However, the following example enumerates the entire collection even though the predicate matches the first item.
(Thanks for the friendlier code Shlomo)
void Main()
{
var entities = Observable.Defer(() => GetObservable().Concat());
Entity result = null;
var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i);
result.Dump();
buildCalled.Dump();
}
// Define other methods and classes here
public IEnumerable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.Select(i => Observable.Return(BuildEntity(i)));
}
public int buildCalled = 0;
public Entity BuildEntity(EntityTableRow entityRow)
{
buildCalled++;
return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal };
}
public class Entity
{
public int RowId { get; set; }
public string StringVal { get; set; }
}
public class EntityTableRow
{
public int Id { get; set; }
public string StringVal { get; set; }
}
Is this the expected behavior? Is there a way to defer the enumeration of the objects (specifically the building in this case) until truly needed?
The following is Linqpad-friendly code equivalent to what you have:
void Main()
{
var entities = Observable.Defer(() => GetObservable().Concat());
Entity result = null;
var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i);
result.Dump();
buildCalled.Dump();
}
// Define other methods and classes here
public IEnumerable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.Select(i => Observable.Return(BuildEntity(i)));
}
public int buildCalled = 0;
public Entity BuildEntity(EntityTableRow entityRow)
{
buildCalled++;
return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal };
}
public class Entity
{
public int RowId { get; set; }
public string StringVal { get; set; }
}
public class EntityTableRow
{
public int Id { get; set; }
public string StringVal { get; set; }
}
If you change GetObservable to the following, you'll get the desired result:
public IObservable<IObservable<Entity>> GetObservable()
{
var rows = new List<EntityTableRow>
{
new EntityTableRow { Id = 1, StringVal = "One"},
new EntityTableRow { Id = 2, StringVal = "Two"},
};
return rows.ToObservable().Select(i => Observable.Return(BuildEntity(i)));
}
It appears the implementation of Concat<TSource>(IEnumerable<IObservable<TSource>>) is eager in evaluating the enumerable, whereas the implementation of Concat<TSource>(IObservable<IObservable<TSource>>) and ToObservable<TSource>(IEnumerable<TSource>) maintain laziness appropriately. I can't say I know why.

Comparing two lists "List<Category>" where Category is my class

I have to find out the difference between two lists of class Category.
My Category class has these properties:
public class Category
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsQuantitative
{
get { return Products.Any(x => x.IsMultiPart); }
}
public List<Product> Products { get; set; }
public string Image { get; set; }
public string Description { get; set; }
}
Try this
var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();
link
I would sort the two lists by Id first.
Then run through it and compare the Objects.
This is a good Object Comparer:
https://www.nuget.org/packages/CompareNETObjects/
Here a little example:
//Here you set the config like you want to have it compared
ComparisonConfig comparisonConfig = new ComparisonConfig()
{
CompareChildren = true,
CompareFields = true,
CompareReadOnly = true,
CompareProperties = true,
MaxDifferences = 1,
MaxByteArrayDifferences = 1
};
CompareLogic comparer = new CompareLogic() { Config = comparisonConfig };
list1 = list1.OrderBy(x => x.Id).ToList();
list2 = list2.OrderBy(x => x.Id).ToList();
for (int i =0;i> list1.count;i++)
{
//Here you get a bool if the two Objects are Equal
bool areEqual = comparer.Compare(list1[i], list2[i]).AreEqual;
//Here you get a List of Differences Objects. It contains Values like "expected and "actual" etc.
var differences = comparer.Compare(list1[i], list2[i]).Differences;
//Here you handle Differences etc.
}

Using contravariance with Func<T, object> selector property

I am designing a generic column definitions class which will act as a selector of properties from entities, all this to make it easier to manage grid presentations of different aspects in a LOB application.
Unfortunately I hit a wall trying to use generic parameter in a class which will be contained in a collection. Example implementation for SettingsContext class below explains what is happening:
public interface IDisplayColumn<in T>
{
string Title { get; set; }
int Order { get; set; }
Func<T, object> Selector { get; }
}
public class DisplayColumn<T>: IDisplayColumn<T>
{
public string Title { get; set; }
public int Order { get; set; }
public Func<T, object> Selector { get; set; }
}
public class ColumnSet
{
public Type TypeHandled { get; set; }
public IEnumerable<IDisplayColumn<object>> Columns { get; set; }
}
public static class ColumnSetTest
{
static ColumnSetTest()
{
// Cannot implicitly convert type 'DisplayColumn<System.Configuration.SettingsContext>' to 'IDisplayColumn<object>'.
// An explicit conversion exists (are you missing a cast?)
IDisplayColumn<object> testSingleColumn = new DisplayColumn<SettingsContext> {Title = "Test", Selector = x => x.Values };
// another test with other type used as a source which should be assignable to DisplayColumn<object>
testSingleColumn = new DisplayColumn<SettingsProvider> { Title="Another test", Selector = x => x.ApplicationName };
// Cannot implicitly convert type 'System.Collections.Generic.List<IDisplayColumn<System.Configuration.SettingsContext>>'
// to 'System.Collections.Generic.IEnumerable<IDisplayColumn<object>>'.
// An explicit conversion exists (are you missing a cast?)
var columnSets = new List<ColumnSet>
{
new ColumnSet
{
TypeHandled = typeof(SettingsContext),
Columns = new List<IDisplayColumn<SettingsContext /* or object */>>
{
new DisplayColumn<SettingsContext> {Title = "Column 1", Order = 1, Selector = x => x.IsReadOnly },
new DisplayColumn<SettingsContext> {Title = "Column 2", Order = 2, Selector = x => x.IsSynchronized },
new DisplayColumn<SettingsContext> {Title = "Column 3", Order = 3, Selector = x => x.Keys }
}
}
};
}
}
How I understand the purpose of covariance and contravariance this is really expected - out parameter should be used for IDisplayColumn testSingleColumn = new DisplayColumn assignment but I need to make Func in parameter generic, out will always be an object.
How to implement such scenario, would it require implementing custom Func or maybe dotnet has already a type suited for such purpose?
Currently the only solution I can see is to create non-generic DisplayColumn class with Func< object, object > Selector property and casting argument to a concrete type in each assignment which is obviously not a great solution. Another option would be to inherit base non-generic DisplayColumn class and put generic selector in inherited generic class but then using this expression when presenting data would require invoking generic method in inherited generic class which is really unacceptable by performance and code quality standards.
If you make your ColumnSet generic as well, then you can specify the type used for the columns enumerable that it returns. The code below will compile, and I think achieve what you are after.
public interface IDisplayColumn<in T>
{
string Title { get; set; }
int Order { get; set; }
Func<T, object> Selector { get; }
}
public class DisplayColumn<T>: IDisplayColumn<T>
{
public string Title { get; set; }
public int Order { get; set; }
public Func<T, object> Selector { get; set; }
}
public class ColumnSet<T>
{
public Type TypeHandled { get; set; }
public IEnumerable<IDisplayColumn<T>> Columns { get; set; }
}
public static class ColumnSetTest
{
static ColumnSetTest()
{
IDisplayColumn<SettingsContext> testSingleColumn = new DisplayColumn<SettingsContext> { Title = "Test", Selector = x => x.Values };
var columnSets = new List<ColumnSet<SettingsContext>>
{
new ColumnSet<SettingsContext>
{
TypeHandled = typeof(SettingsContext),
Columns = new List<IDisplayColumn<SettingsContext>>
{
new DisplayColumn<SettingsContext> {Title = "Column 1", Order = 1, Selector = x => x.IsReadOnly },
new DisplayColumn<SettingsContext> {Title = "Column 2", Order = 2, Selector = x => x.IsSynchronized },
new DisplayColumn<SettingsContext> {Title = "Column 3", Order = 3, Selector = x => x.Keys }
}
}
};
}
}
After thorough investigation I found out the solution would require mixing covariance and contravariance which is not supported currently. The closest solution (which compiles) actually does not allow easy access to IDisplayColumn.Selector as T argument in IColumnSet.Columns will be visible as object not IDisplayColumn so it's not an option:
public interface IDisplayColumn<in T>
{
string Title { get; set; }
int Order { get; set; }
Func<T, object> Selector { get; }
}
public class DisplayColumn<T> : IDisplayColumn<T>
{
public string Title { get; set; }
public int Order { get; set; }
public Func<T, object> Selector { get; set; }
}
public interface IColumnSet<out T>
{
Type TypeHandled { get; }
IEnumerable<T> Columns { get; }
}
public class ColumnSet<T> : IColumnSet<IDisplayColumn<T>>
{
public Type TypeHandled
{
get
{
return typeof(T);
}
}
public IEnumerable<IDisplayColumn<T>> Columns { get; set; }
}
I ended up translating Func<,> using expressions when creating which is a one-time operation with minimal overhead of casting when using selector:
public interface IDisplayColumn
{
string Title { get; set; }
bool Visible { get; set; }
int Order { get; set; }
Func<object, object> Value { get; }
T GetValue<T>(object source);
}
public class DisplayColumn<T>: IDisplayColumn
{
public string Title { get; set; }
public bool Visible { get; set; }
public int Order { get; set; }
public Func<object, object> Value { get; set; }
public override string ToString()
{
return Title;
}
public TValue GetValue<TValue>(object source)
{
return (TValue)Convert.ChangeType(Value(source), typeof(TValue));
}
public Func<T, object> Selector
{
set
{
Value = value.ConvertObject<T>();
}
}
}
public interface IColumnSet
{
Type TypeHandled { get; }
IEnumerable<IDisplayColumn> Columns { get; }
}
public class ColumnSet<T>: IColumnSet
{
public Type TypeHandled
{
get
{
return typeof(T);
}
}
public IEnumerable<IDisplayColumn> Columns { get; set; }
}
public static Func<object, object> ConvertObject<T>(this Func<T, object> func)
{
Contract.Requires(func != null);
var param = Expression.Parameter(typeof(object));
var convertedParam = new Expression[] { Expression.Convert(param, typeof(T)) };
Expression call;
call = Expression.Convert(
func.Target == null
? Expression.Call(func.Method, convertedParam)
: Expression.Call(Expression.Constant(func.Target), func.Method, convertedParam)
, typeof(object));
var delegateType = typeof(Func<,>).MakeGenericType(typeof(object), typeof(object));
return (Func<object, object>)Expression.Lambda(delegateType, call, param).Compile();
}
And the example of usage:
private class TestObject1
{
public int Id { get; set; }
public string Name { get; set; }
}
IDisplayColumn objectColumn = new DisplayColumn<TestObject1> { Title = "Column 1", Selector = (x) => x.Name };
var columnSets = new List<IColumnSet>
{
new ColumnSet<TestObject1>
{
Columns = new List<IDisplayColumn>
{
new DisplayColumn<TestObject1> { Title = "Column 1", Order = 3, Selector = x => x.Id },
new DisplayColumn<TestObject1> { Title = "Column 2", Order = 2, Selector = x => x.Name },
new DisplayColumn<TestObject1> { Title = "Column 3", Order = 1, Selector = x => x.Id.ToString(CultureInfo.InvariantCulture) + x.Name.ValueOrEmpty() },
}
}
};
So I will give myself the credit for this problem but if somebody can suggest a nicer solution using generics and variance, please feel free to post it as I will be happy to change the solution.

How to copy a List<> to another List<> with Comparsion in c#

I an having Two Lists. I want to get the matched and unmatched values based on ID and add the results to another List. I can get both of these using Intersect/Except.
But I can get only ID in the resultant variables (matches and unmatches) . I need all the properties in the Template.
List<Template> listForTemplate = new List<Template>();
List<Template1> listForTemplate1 = new List<Template1>();
var matches = listForTemplate .Select(f => f.ID)
.Intersect(listForTemplate1 .Select(b => b.ID));
var ummatches = listForTemplate .Select(f => f.ID)
.Except(listForTemplate1.Select(b => b.ID));
public class Template
{
public string ID{ get; set; }
public string Name{ get; set; }
public string Age{ get; set; }
public string Place{ get; set; }
public string City{ get; set; }
public string State{ get; set; }
public string Country{ get; set; }
}
public class Template1
{
public string ID{ get; set; }
}
If you don't want to implement IEquality for this simple task, you can just modify your LINQ queries:
var matches = listForTemplate.Where(f => listForTemplate1.Any(b => b.ID == f.ID));
and
var unmatches = listForTemplate.Where(f => listForTemplate1.All(b => b.ID != f.ID));
You might want to check for null before accessing ID, but it should work.
You are looking for the overloaded function, with the second parameter IEqualityComparer. So make your comparer ( example: http://www.blackwasp.co.uk/IEqualityComparer.aspx ), and use the same comparer in intersect / except.
And for the generic part: maybe you should have a common interface for templates e.g. ObjectWithID describing that the class have a string ID property. Or simply use dynamic in your comparer (but I think this is very-very antipattern because you can have run time errors if using for the bad type).
You also have a problem: intersecting two collections with two different types will result in a collection of Object (common parent class). Then you have to cast a lot (antipattern). I advise you to make a common abstract class/interface for your template classes, and it is working. If you need to cast the elements back, do not cast, but use the visitior pattern: http://en.wikipedia.org/wiki/Visitor_pattern
Example (good):
static void Main(string[] args)
{
// http://stackoverflow.com/questions/16496998/how-to-copy-a-list-to-another-list-with-comparsion-in-c-sharp
List<Template> listForTemplate = new Template[] {
new Template(){ID = "1"},
new Template(){ID = "2"},
new Template(){ID = "3"},
new Template(){ID = "4"},
new Template(){ID = "5"},
new Template(){ID = "6"},
}.ToList();
List<Template1> listForTemplate1 = new Template1[] {
new Template1(){ID = "1"},
new Template1(){ID = "3"},
new Template1(){ID = "5"}
}.ToList();
var comp = new ObjectWithIDComparer();
var matches = listForTemplate.Intersect(listForTemplate1, comp);
var ummatches = listForTemplate.Except(listForTemplate1, comp);
Console.WriteLine("Matches:");
foreach (var item in matches) // note that item is instance of ObjectWithID
{
Console.WriteLine("{0}", item.ID);
}
Console.WriteLine();
Console.WriteLine("Ummatches:");
foreach (var item in ummatches) // note that item is instance of ObjectWithID
{
Console.WriteLine("{0}", item.ID);
}
Console.WriteLine();
}
}
public class ObjectWithIDComparer : IEqualityComparer<ObjectWithID>
{
public bool Equals(ObjectWithID x, ObjectWithID y)
{
return x.ID == y.ID;
}
public int GetHashCode(ObjectWithID obj)
{
return obj.ID.GetHashCode();
}
}
public interface ObjectWithID {
string ID { get; set; }
}
public class Template : ObjectWithID
{
public string ID { get; set; }
public string Name { get; set; }
public string Age { get; set; }
public string Place { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class Template1 : ObjectWithID
{
public string ID { get; set; }
}
Output:
Matches:
1
3
5
Ummatches:
2
4
6
Press any key to continue . . .
For comparison, this should also work (the first part is a variation on #MAV's answer):
var matches = from item in listForTemplate
join id in listForTemplate1 on item.ID equals id.ID
select item;
var unmatches = listForTemplate.Where(item => matches.All(elem => elem.ID != item.ID));
matches and unmatches will both be IEnumerable<Template> which is the type you require.
However, MAV's answer works fine so I'd go for that one.
As mentioned, Implement the IEqualityComparer<T> interface.
IEqualityComparer<T> MSDN
Then use this as an argument in your method for Except() and Intersect()
Intersect
There is a good example of how to do so on the link for the Intersect() method.
If you don't absolutely have to use LINQ, why not code something like this?
var matches = new List<Template>();
var unmatches = new List<Template>();
foreach (var entry in listForTemplate)
{
bool matched = false;
foreach (var t1Entry in listForTemplate1)
{
if (entry.ID == t1Entry.ID)
{
matches.Add(entry);
matched = true;
break;
}
}
if (!matched)
{
unmatches.Add(entry);
}
}
A disadvantage of the LINQ approach is that you're traversing the lists twice.

Categories

Resources