patterncsharpMinor
Refactor Linq grouping
Viewed 0 times
linqrefactorgrouping
Problem
All of the class here share these same property
Country, Total and Date.
Total property are integer in some classes and decimal in some classed.
The extension method below has a lot of duplication. i have tried to refactor it using interface but i can't find a way to refactor it at the last step on selection since it need different class
```
public static class TotalApprovedPOAmountStatisticExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item.Country))
{
item.Country = "";
}
}
totalUserStatistic = totalUserStatistic
.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new TotalApprovedPOAmountStatistic()
{ Country = groupedUser.Key.Country, Total = groupedUser.Sum(item => item.Total), Date = groupedUser.Key.Date }).ToList();
}
}
public static class TotalPOStatisticListExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item.Country))
{
item.Country = "";
}
}
totalUserStatistic = totalUserStatistic
.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new TotalPOStatistic() { Country = groupedUser.Key.Country, Total = groupedUser.Sum(item => item.Total), Date = groupedUser.Key.Date }).ToList();
}
}
public static class TotalProjectAmountStatisticListExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item
Country, Total and Date.
Total property are integer in some classes and decimal in some classed.
The extension method below has a lot of duplication. i have tried to refactor it using interface but i can't find a way to refactor it at the last step on selection since it need different class
```
public static class TotalApprovedPOAmountStatisticExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item.Country))
{
item.Country = "";
}
}
totalUserStatistic = totalUserStatistic
.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new TotalApprovedPOAmountStatistic()
{ Country = groupedUser.Key.Country, Total = groupedUser.Sum(item => item.Total), Date = groupedUser.Key.Date }).ToList();
}
}
public static class TotalPOStatisticListExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item.Country))
{
item.Country = "";
}
}
totalUserStatistic = totalUserStatistic
.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new TotalPOStatistic() { Country = groupedUser.Key.Country, Total = groupedUser.Sum(item => item.Total), Date = groupedUser.Key.Date }).ToList();
}
}
public static class TotalProjectAmountStatisticListExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic)
{
foreach (var item in totalUserStatistic)
{
if (string.IsNullOrWhiteSpace(item
Solution
You can use an interface and a generic method to remove the code duplication:
Important here is the
If the
Also, your extension method should actually return something, because it won't change the
public interface IStatistic
{
string Country {get; set;}
DateTime Date {get; set;}
Decimal Total {get; set;}
}
public static class StatisticExtension
{
public static void MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic) where T : IStatistic, new()
{
foreach (var item in totalUserStatistic)
if (string.IsNullOrWhiteSpace(item.Country))
item.Country = "";
totalUserStatistic = totalUserStatistic.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new T()
{
Country = groupedUser.Key.Country,
Total = groupedUser.Sum(item => item.Total),
Date = groupedUser.Key.Date
}).ToList();
}
}Important here is the
new() constraint, which allows us to create an instance of T.If the
Total property of a class is int instead of decimal, we can make use of an explicit interface implementation:public class BlaStatistic : IStatistic
{
public string Country {get; set;}
public DateTime Date {get; set;}
public Int32 Total {get; set;}
Decimal IStatistic.Total
{
get { return Convert.ToDecimal(Total); }
set { Total = Convert.ToInt32(value); }
}
}Also, your extension method should actually return something, because it won't change the
IEnumerable you pass in:public static IEnumerable MergeNullAndEmplyCountry(this IEnumerable totalUserStatistic) where T : IStatistic, new()
{
...
return totalUserStatistic.GroupBy...
}Code Snippets
public interface IStatistic
{
string Country {get; set;}
DateTime Date {get; set;}
Decimal Total {get; set;}
}
public static class StatisticExtension
{
public static void MergeNullAndEmplyCountry<T>(this IEnumerable<T> totalUserStatistic) where T : IStatistic, new()
{
foreach (var item in totalUserStatistic)
if (string.IsNullOrWhiteSpace(item.Country))
item.Country = "";
totalUserStatistic = totalUserStatistic.GroupBy(item => new { item.Country, item.Date })
.Select(groupedUser => new T()
{
Country = groupedUser.Key.Country,
Total = groupedUser.Sum(item => item.Total),
Date = groupedUser.Key.Date
}).ToList();
}
}public class BlaStatistic : IStatistic
{
public string Country {get; set;}
public DateTime Date {get; set;}
public Int32 Total {get; set;}
Decimal IStatistic.Total
{
get { return Convert.ToDecimal(Total); }
set { Total = Convert.ToInt32(value); }
}
}public static IEnumerable<T> MergeNullAndEmplyCountry<T>(this IEnumerable<T> totalUserStatistic) where T : IStatistic, new()
{
...
return totalUserStatistic.GroupBy...
}Context
StackExchange Code Review Q#31674, answer score: 4
Revisions (0)
No revisions yet.