Problem with lists, polymorphism and casting in C# - c#

Good afternoon, I am looking to transfer a list of objects that implement a certain interface ("IRecord"), what I do is to filter in a new list the objects that implement the interface in the following case "IEntry", until there is no problem, however, I have problems when I try to caste the filtered list to the type "IList" to use the properties that this last one has, this produces an exception, how can I solve this, Is there a way to avoid going through the whole list, and create a new one again?
interface IRecord
{
string Details { get; set; }
}
interface IEntry : IRecord
{
decimal TotalValue { get; set; }
}
interface IEgress : IRecord
{
string Type { get; set; }
}
class Entry : IEntry
{
public string Details { get; set; }
public decimal TotalValue { get; set; }
public void Foo() { }
}
class Egress : IEgress
{
public string Details { get; set; }
public string Type { get; set; }
}
This is the code I am trying to execute
var records = new List<IRecord>() { new Entry() { Details = "foo" }, new Egress() { Details = "bar" } };
var filteredList = records.Where(entry => entry is Entry).ToList();
var sum = (IList<IEntry>)filteredList;
var x = sum.Sum(en => en.TotalValue);

As already mentioned in comments you can Cast your query before calling ToList()
var filteredList = records.Where(entry => entry is Entry).Cast<IEntry>().ToList();
So the end result would be
var records = new List<IRecord>()
{
new Entry() { Details = "foo", TotalValue = 12 },
new Egress() { Details = "bar" }
};
var filteredList = records.Where(entry => entry is Entry).Cast<IEntry>().ToList();
var sum = (IList<IEntry>)filteredList;
var x = sum.Sum(en => en.TotalValue);
I added a value to your Entry type too, which then allows you to prove your code works :D
Here is a link to Microsoft document on inheritance

Related

LiveCharts2 populating chart with Entity Framework

I'm starting with Livecharts2 (I did not try previous versions) and I'm not sure how to bind data with Entity Framework.
I need to display a chart with warehouse name and the quantity of access of each.
This is what I already have:
List<Access> access = context.Access.ToList();
var countAccess = access
.GroupBy(acc => acc.IdWarehouse)
.Select(group => new
{
Warehouse = group.Key,
Quantity = group.Count()
});
List<int> listQt = new List<int>();
List<int> list_warehouses = new();
foreach (var item in countAccess)
{
listQt.Add(item.Quantity);
list_warehouses.Add(item.Warehouse);
}
cartesianChart1.Series = new ISeries[]
{
new LineSeries<int>
{
Values = listQt,
Name = "Quantity"
},
new ColumnSeries<int>
{
Values = list_warehouses,
Name = "Warehouse"
}
};
My model classes:
public partial class Access
{
public int IdAccess { get; set; }
public byte IdWarehouse { get; set; }
}
public partial class Warehouse
{
public byte IdWarehouse { get; set; }
public string Name{ get; set; } = null!;
}
This code works with the IdWarehouse but Name, is there a better way to do it, instead of creating new list, foreach etc? I'm not sure if it is unnecessary
I tried with List<string> to get the warehouse's names, but got an exception cause is not implemented yet by creator/s

C# group by a column and form hierarchical data with other columns

I am trying to group a column and form the the rest of the columns as child, hierarchical data:
I am trying to group by Code and form the parent and child relationship from a flat list, below is the hierarchical data I am trying to form:
source list:
public class ItemAssignmentFlatList
{
public int Code { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public int ItemCode{ get; set; }
public DateTime EffectiveDate{ get; set; }
public string Area{ get; set; }
public string TaxCode{ get; set; }
public string LocationId { get; set; }
}
Need to convert above flat list into below List of hierarchical data:
public class ItemInfo
{
public int Code { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public List<TaxInfo> TaxPlan { get; set; }
}
public class TaxPlan
{
public int ItemCode{ get; set; }
public DateTime EffectiveDate{ get; set; }
public string Area{ get; set; }
public string TaxCode{ get; set; }
public string LocationId { get; set; }
}
Need hierarchical list with above flat data list with C# extension methods.
I have below code, but looking for clean code to reduce number of lines:
var items= results.GroupBy(x => new { x.Code, x.Type });
List<ItemInfo> result = new List<ItemInfo>();
foreach (var group in items)
{
var taxPlans = group.
Select(y => new TaxPlan
{
TaxArea = y.TaxArea,
ItemCode = y.ItemCode
});
var itemInfo= new ItemInfo
{
Code = group.FirstOrDefault().Code,
Type = group.FirstOrDefault().Type,
Description = group.FirstOrDefault().Description,
TaxPlan = taxPlans.ToList()
};
result.Add(itemInfo);
}
Something like this?:
var input = new List<ItemAssignmentFlatList>(){
new ItemAssignmentFlatList{
Code = 1,
Area = "a"
},
new ItemAssignmentFlatList{
Code = 1,
Area = "b"
},
new ItemAssignmentFlatList{
Code = 2,
Area = "c"
}
};
input
.GroupBy(
x => x.Code,
(int code, IEnumerable<ItemAssignmentFlatList> items) =>
{
var first = items.FirstOrDefault();
var key = new ItemInfo
{
Code = first.Code
//, ...
};
var plan = items.
Select(y => new TaxPlan
{
Area = y.Area
//, ...
});
return new
{
key = key,
items = plan
};
}
).Dump();
Whenever you have a sequence of similar object, and you want to make "Items with their SubItems", based on common properties in your source sequence, consider to use one of the overloads of Enumerable.GroupBy
Because you don't just want "Groups of source items" but you want to specify your output, consider to use the overload that has a parameter resultSelector.
parameter keySelector: what should all elements in a group have in common
parameter resultSelector: use the common thing, and all elements that have this common thing to make one output element.
.
IEnumerable<ItemAssignmentFlatList> flatItemAssignments = ...
IEnumerable<ItemInfo> items = flatItemAssignments
// make groups with same {Code, Type, Description}
.GroupBy(flatItemAssignment => new {Code, Type, Description},
// parameter resultSelector: take the common CodeTypeDescription,
// and all flatItemAssignments that have this common value
// to make one new ItemInfo
(codeTypeDescription, flatItemAssignmentsWithThisCodeTypeDescription) => new ItemInfo
{
Code = codeTypeDescription.Code,
Type = codeTypeDescription.Type,
Description = codeTypeDescription.Description,
TaxPlans = flatItemAssignmentsWithThisCodeTypeDescription
.Select(flatItemAssignment => new TaxPlan
{
ItemCode = flatItemAssignment.ItemCode,
EffectiveDate = flatItemAssignment.EffectiveDate,
Area = flatItemAssignment.Area,
...
})
.ToList(),
});

cannot implicity convert type System.Collections.GenericList<AnonymousType#1>

Please have patience with me I'm new to linq and have a question about a couple of errors that I am not understanding any help would be greatly appreciated.
the error I am receiving in the title of my question.
my childproduct variable returns every single character indiviuallly I would like them to be a string version of the productId and Childtext parameters.
Code:
public class AOAPlusChildModel
{
public List<string> LongName { get; set; }
public List<string> Text { get; set; }
public List<string> ProductId { get; set; }
public static List<AOAPlusChildModel> GetChildProducts()
{
List<AOAPlusChildModel> cp = new List<AOAPlusChildModel>();
List<AoaUserDefinedVWGetAOAPlusProducts> ChildProductsLists = AoaSvcClient.Client.Context.AoaUserDefinedVWGetAOAPlusProductss.Where(a => a.MasterProductFlag == false && a.Affiliate == "VA").ToList();
var childProducts = ChildProductsLists.SelectMany(p => p.LongName, (id, childtext) =>
new { ProductId = id.ProductId, Text = childtext }).ToList();
cp = childProducts.ToList();
return cp;
}
}
Your variable cp is a List<AOAPlusChildModel> but the linq query is projecting an anonymous type. Instead of creating a new anonymous type create a new AOAPlusChildModel
return ChildProductsLists.SelectMany(p => p.LongName,
(id, childtext) =>
new AOAPlusChildModel {
ProductId = id.ProductId,
Text = childtext }).ToList();
Reason for following errors are that you perform ChildProductsLists.SelectMany(p => p.LongName) which basically now returns a collection of strings - this collection of strings you are trying to assign as a new AOAPlusChildModel object which does not hold string properties but List<string> properties.
I think your model should look like:
public string LongName { get; set; }
public string Text { get; set; }
public string ProductId { get; set; }

C# Merge properties from two (or more) lists based on common property

I have three lists of objects each of which are linked to one other list by a single common property, Parent and Node in the following hierarchy: Model -> Intermediate -> Results. I have the following code:
class Result
{
public string Name { get; set; }
public int Node{ get; set; }
public int Parent{ get; set; }
}
class Intermediate
{
public int Node{ get; set; }
public int Parent{ get; set; }
}
class Model
{
public string Name { get; set; }
public int Node{ get; set; }
public int Parent{ get; set; }
}
public class Example
{
public static void Main()
{
List<Result> results = new List<Result>();
List<Intermediate> intermediates = new List<Intermediate>();
List<Model> models = new List<Model>();
// Example objects in the list
results.Add(new Result() { Name = "", Parent = 21, Node = 101 });
intermediates.Add(new Part() { Parent = 11, Node = 21 });
models.Add(new Part() { Name = "ABCD", Parent = 1, Node = 11 });
...
}
}
As can be seen the Model object links to Intermediate object via model.Node and intermediate.Parent, and the Intermediate object links to Results object via intermediate.Node and results.Parent.
Note the lists can contain thousands of items, each added using a similar format as above.
What I want to be able to do is add the names from the Model objects in list to the matching Results objects in the results list.
My thinking is that I can loop through each object in the Intermediate list and find (using LINQ) the Result object where intermediate.Node = result.Parent, and then either replace the value of the result.Parent with intermediate.Parent, or add a new Grandparent property to the Result object in which to put the intermediate.Parent. Then repeat the process looping through each of the objects in the models list finding the matching Result object and adding the Name.
So I guess my question is, is this the best way of doing this, or is there a more efficient way? I have many lists where the same will have to be repeated, so was wondering if there was a better way as it can be quite slow looping through every object. Also is there a way to get from the first list directly to the third list.
I hope this is well enough explained. I am quite a beginner when it comes to C#.
You actually have Results -> Intermediate -> Model instead of Model -> Intermediate -> Results.
To speed the process of removing the Intermediate, build a dictionary. Then you can do a simple select on Results using the dictionary to convert.
var intermediateDict=intermediates.ToDictionary(key=>key.Node,val=>val.Parent);
var newresults=results.Select(r=>new Result {
Name=r.Name,
Node=r.Node,
Parent=intermediateDict[r.Parent]
});
You can also do joins to get the final answer.
It looks a foreach loop can be used to get to the result (leaf) nodes and assign the model name to result nodes:
var theModel = models.First(); // select a model
foreach (var interm in intermediates.Where(x => x.Parent == theModel.Node))
{
foreach (var res in results.Where(x => x.Parent == interm.Node))
{
res.Name = theModel.Name;
}
}
Smells like Composite Pattern what you talk about here.
And you can use HashSet to keep your values to perform it fast.
public class Item
{
public Item(int itemNode)
{
Node = itemNode;
Children = new HashSet<Item>();
}
public int Node { get; set; }
public Item Parent { get; set; }
private HashSet<Item> Children { get; set; }
public bool Add(Item item)
{
item.Parent = this;
return Children.Add(item);
}
public List<Item> Find(Func<Item, bool> predicate)
{
var found = new List<Item>();
if (predicate(this)) found.Add(this);
Collect(predicate, found);
return found;
}
public void Collect(Func<Item, bool> predicate, List<Item> collected = null)
{
collected = collected ?? new List<Item>();
collected.AddRange(Children.Where(predicate).ToList());
foreach (var child in Children)
{
child.Collect(predicate, collected);
}
}
}
public class Model : Item //this is your model
{
public string Name { get; set; }
public Model(int itemNode, string name) : base(itemNode)
{
Name = name;
}
public List<Item> GetNamesMatchingWith(Func<Item, bool> predicate)
{
return Find(predicate);
}
}
public class Example
{
public static void Main()
{
var root = new Model(0, "root");
var one = new Model(1, "1");
var two = new Model(2, "2");
var tree = new Model(3, "3");
root.Add(one);
root.Add(two);
root.Add(tree);
var a = new Model(4, "a");
var b = new Model(5, "b");
two.Add(a);
two.Add(b);
var namesMatchingWith = root.GetNamesMatchingWith(x=> x.Parent!=null && x.Parent.Node == 2);
Console.ReadKey();
}
}
Hope it inpires you..

How to select all the values of an object's property on a list of typed objects in .Net with C#

Ugh, how do I explain this one... Probably a simple question but my mind is fried.
Suppose I have this class:
public class NestedObject
{
public string NestedName { get; set; }
public int NestedIntValue { get; set; }
public decimal NestedDecimalValue { get; set; }
}
public class SomeBigExternalDTO
{
public int Id { get; set; }
public int UserId { get; set; }
public int SomeIntValue { get; set; }
public long SomeLongValue { get; set; }
public decimal SomeDecimalValue { get; set; }
public string SomeStringValue { get; set; }
public NestedObject SomeNestedObject { get; set; }
// ... thousands more of these properties... inherited code
}
And the class I'd like to populate is here:
public class MyResult
{
public int UserId { get; set; } // user id from above object
public string ResultValue { get; set; } // one of the value fields from above with .ToString() executed on it
}
What I'd like to do is create a helper to return the property values (a cross section is the best way I could describe it I guess) of all instances in a list of this object:
var foo = new List<SomeBigExternalDTO>();
foo = GetMyListOfSomeBigExternalDTO();
public static List<MyResult> AwesomeHelper(List<SomeBigExternalDTO> input, SearchableProperty thePropertyIWant)
{
// some magic needs to happen here...
}
The tricky part here is I want to dynamically pass in the property based on a link selector (I have no clue how to do this):
var output = AwesomeHelper(GetMyListOfSomeBigExternalDTO(), x => x.SomeIntValue);
var output2 = AwesomeHelper(GetMyListOfSomeBigExternalDTO(), x => x.SomeNestedObject.NestedIntValue);
And this should return a list of MyResult objects with the UserId and SomeIntValue.ToString() corresponding to each item in the input list.
Wow, I really hope this makes sense. Please let me know if this is not clear I'll provide more details. I'm really hoping this is something baked into the libraries that I've overlooked.
Any ideas on I'd accomplish this?
You could implement it as an extension method:
public static IEnumerable<MyResult> AwesomeHelper(this IEnumerable<SomeBigExternalDTO> input,
Func<SomeBigExternalDTO, int> intMapper)
{
foreach (var item in input)
yield return new MyResult()
{
UserId = item.UserId,
ResultValue = intMapper(item)
};
}
Now you can use it like this:
var output = GetMyListOfSomeBigExternalDTO().AwesomeHelper( x => x.SomeIntValue);
var output2 = GetMyListOfSomeBigExternalDTO().AwesomeHelper( x => x.SomeNestedObject.NestedIntValue);
Having said that - dont' do that - it somehow looks like you are reinventing what Linq already offers you, you can do just the same using only Linq:
var output = GetMyListOfSomeBigExternalDTO().Select( x=> new MyResult()
{
UserId = item.UserId,
ResultValue = x.SomeIntValue
});
var output2 = GetMyListOfSomeBigExternalDTO().Select( x=> new MyResult()
{
UserId = item.UserId,
ResultValue = x.SomeNestedObject.NestedIntValue
});
Often when trying to create a general purpose list operator you end up reimplementing what LINQ already offers you.
Here's the LINQ code for what you're after (without an AwesomeHelper function):
var results = list.Select(l => new MyResult()
{
UserId = l.UserId,
ResultValue = l.SomeDecimalValue.ToString()
}).ToList();
Fairly simple.
If you want to have an AwesomeHelper function as you requested then it looks like this:
public static List<MyResult> AwesomeHelper(
List<SomeBigExternalDTO> input,
Func<SomeBigExternalDTO, object> selector)
{
return input
.Select(i => new MyResult()
{
UserId = i.UserId,
ResultValue = selector(i).ToString()
})
.ToList();
}
And the calling code look like this:
var results = AwesomeHelper(list, x => x.SomeIntValue);
To me, though, this is now less readable than the LINQ option. Now there is some magic being wrought and it's hard to work out what.
I have an alternative that will give you the best of both worlds.
First, define an extension method called ToMyResult that maps a single SomeBigExternalDTO instance into a single MyResult with a field selector, like this:
public static class AwesomeHelperEx
{
public static MyResult ToMyResult(
this SomeBigExternalDTO input,
Func<SomeBigExternalDTO, object> selector)
{
return new MyResult()
{
UserId = input.UserId,
ResultValue = selector(input).ToString()
};
}
}
Now the calling code is crystal clear, flexible and concise. Here it is:
var results = (
from item in list
select item.ToMyResult(x => x.SomeLongValue)
).ToList();
I hope this helps.

Categories