Obtain Properties in Child Classes in IEnumerable of Base Class - c#

If I have an collection of a given entity, I'm able to obtain the properties for entity like so:
var myCollection = new List<Foo>();
entities.GetType().GetGenericArguments()[0].GetProperties().Dump();
However, I'm having some difficulties listing out the properties if my collection is an IEnumerable of a base class and populated with derived classes.
public class Foo
{
public string One {get;set;}
}
public class Bar : Foo
{
public string Hello {get;set;}
public string World {get;set;}
}
// "Hello", "World", and "One" contained in the PropertyInfo[] collection
var barCollection = new List<Bar>() { new Bar() };
barCollection.GetType().GetGenericArguments()[0].GetProperties().Dump();
// Only "One" exists in the PropertyInfo[] collection
var fooCollection = new List<Foo>() { new Bar() };
fooCollection.GetType().GetGenericArguments()[0].GetProperties().Dump();
Is there anyway to get the types of the items in the collection even though the collection is declared using the base class?

That is because you are obtaining the properties from the type represented by the type parameter T which is Foo, and Foo only has the One property.
To get all possible properties, you need to go through the types of all the objects in the list like this:
var allProperties = fooCollection
.Select(x => x.GetType())
.Distinct()
.SelectMany(t => t.GetProperties())
.ToList();

Related

Filter out some properties from a list of objects

I have a list of objects (MyObject) which has 10 properties.
Class MyObject{
string F1,
string F2,
....
string F10
}
var myList = new List<MyObject> ()
From that mylist I have to filter out some property and get a new list of selected items depending on the input provided in a List of string.
var requiredFlields = new List<String> {"F1", "F2"}
I know this :
var o1 = myList.Select(a => new { a.F1, a.F2 }).ToList();
but it doesn't allow me to use the requiredFields list for filtering.
Is there anyway to achieve that?
You can get property details from class, using GetProperties() function.Use it to get details of all properties.
Iterate through each property and check name of that property is present in class or not.
Sample code:
PropertyInf[] propertiesInfo = MyObject.GetType().GetProperties();
foreach(PropertyInfo item in propertiesInfo)
{
if(requiredFields.Contains(item.Name))
{
//Do your operation here
}
}
With the help of PropertyInfo you can check name of property, type of property, GetSetMethod()
For more details: PropertyInfo Class

Find a derived class in a list of its base class

So I have a List of BaseClass and I've filled it with several instances of derived classes (only one of each derived class) so that we have something like:
List<BaseClass> myList = new List<BaseClass>();
myList.Add(new DerivedClassA());
myList.Add(new DerivedClassB());
myList.Add(new DerivedClassC());
Now I want to be able to search myList with something like this:
public void FindClass (BaseClass class){ //class is a derived class
//find index or object of type class
//so that if class is a DerivedClassB
//we return the first DerivedClassB in myList
}
Is this possible? I know I can give each DerivedClass a name property and find it by it's name but I don't want to have to do that.
Another solution would be to use 'OfType<>' to filter the list
public class Base { }
public class DerivedA : Base { }
public class DerivedB : Base { }
List<Base> instances = new List<Base>();
instances.Add(new DerivedA());
instances.Add(new DerivedB());
var results = instances.OfType<DerivedA>().FirstOrDefault();
EDIT - This is a way of creating a method that would do the search
T Find<T>() where T : Base {
return _Instances.OfType<T>().FirstOrDefault();
}
If you pass in an instance of DerivedClassB, you can find all instances of DerivedClassB by comparing the actual type of the instance passed in and of the instances in the list:
public IEnumerable<BaseClass> FindClass (BaseClass #class){
return myList.Where(c => c.GetType() == #class.GetType());
}
You can do this with the is operator. It tells you if an object is of a given type. Add a little LINQ and you get:
var firstB = myList
.Where(c => c is DerivedClassB)
.First();

Using LINQ to loop through inner class properties in outer class collection

Leveraging off the Q&As dealing with looping through an object's properties (https://stackoverflow.com/questions/15586123/loop-through-object-and-get-properties, Loop Through An Objects Properties In C#), where you have:
a collection of Class1 objects (i.e. listObj1)
each Class1 contains a collection of Class2 objects (i.e. dictObj2)
How would you:
efficiently determine the properties of the inner class (Class2)
loop through the the properties of the inner class (Class2)
loop through the collection of Class1 objects (listObj1) selecting all instances of the the Class2 property
output the collection of Class2 property (e.g. the first iteration would return a collection of MeasurementA, one from each Class1 object).
and group the collection by Class1.PropertyA and Class1.PropertyB
Please find below a rough map of the classes involved.
I have been trying to use a LINQ query without success. Any ideas or guidance would be greatly appreciated.
class MainClass {
List<Class1> listObj1
}
class Class1 {
// a number of fields including...
int PropertyA { get; set; }
int PropertyB { get; set; }
Dictionary<int, Class2> dictObj2 { get; set; }
}
class Class2 {
// a number of fields all of type double...
double MeasurementA { get; set; }
double MeasurementB { get; set; }
double MeasurementC { get; set; }
}
Given data:
MainClass mainClass = new MainClass();
mainClass.listObj1 = new List<Class1>()
{
new Class1() {
dictObj2 = new Dictionary<int,Class2>() {
{ 1, new Class2() { MeasurementA = 2.0, MeasurementB = 3.0, MeasurementC = 4.0 }},
{ 2, new Class2() { MeasurementA = 5.0, MeasurementB = 6.0, MeasurementC = 7.0 }}
}
}
};
you can write with LINQ:
var fields = typeof(Class2)
// Get Properties of the ClassB
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
// Map each PropertyInfo into collection of its values from c1.dictObj2
.SelectMany(pi => mainClass.listObj1
.SelectMany(c1 => c1.dictObj2)
.Select(p => new
{
Property = pi.Name,
Value = pi.GetValue(p.Value)
}))
// Group data with respect to the PropertyName
.GroupBy(x => x.Property, x => x.Value)
// And create proper dictionary
.ToDictionary(x => x.Key, x => x.ToList());
and now you have a Dictionary with keys of ClassB property names and values as List of those properties values.
Efficiently determine the properties of the inner class (Class 2)
Regardless of efficiency, there really is only one way you can do it (assuming you mean at runtime) and that's using Reflection.
Loop through the properties of the inner class (Class 2)
foreach (var prop in instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
Console.WriteLine(prop.Name);
}
loop through the collection of Class1 objects (listObj1) selecting all instances of the the Class2 property
foreach (var obj in mainClass.listObj1)
{
var innerClasses = obj.dictObj2.Values;
// do something with inner classes
}
output the collection of Class2 property (e.g. the first iteration would return a collection of MeasurementA, one from each Class1 object).
foreach (var prop in typeof(Class2).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
foreach (var obj in mainClass.listObj1)
{
foreach (var innerClass in obj.dictObj2.Values)
{
Console.WriteLine(prop.GetValue(innerClass, null));
}
}
}
Not sure why you are so keen on using LINQ here, I think a couple of simple for loops are all you need here.

Map parts of an aggregate to a List<T>

Let us say we have a simple business object:
class SimpleBO
{
public string Field1{get;set;}
public string Field2{get;set;}
}
Also we have a complex Aggregate like that:
class ComplexBO
{
public SimpleBO SimpleBOField {get;set}
public List<SomeClass> ObjectList {get;set;}
public SomeClass Object {get;set;}
}
SomeClass itself has a reference of SimpleBO:
class SomeClass
{
public SimpleBO SimpleBOField {get;set}
}
Now in some part of my program I want to get a list of all distinct simple objects met inside a certain aggreggate. We are using automapper heavily but I did not manage to map it so far. May be a LINQ query is a better option? How would you solve this?
Assuming what you have is:
ComplexBO aggregate = ...
then you should just need:
var objects = aggregate.ObjectList.Select(x => x.SimpleBOField).Concat(
new[] {aggregate.SimpleBOField, aggregate.Object.SimpleBOField }
).Distinct().ToList();
This will give you the distinct object references; if you need distinct value pairs, then either override Equals()/GetHashCode(), or cheat:
var objects = aggregate.ObjectList.Select(x => x.SimpleBOField).Concat(
new[] {aggregate.SimpleBOField, aggregate.Object.SimpleBOField }
).Select(
x => new {x.SimpleBOField.Field1, x.SimpleBOField.Field2}
).Distinct().Select(
x => new SimpleBO {Field1 = x.Field1, Field2 = x.Field2}
).ToList();

Polymorphism with AutoMapper

I have these business classes:
class BaseNode
{
public string name;
}
class CompositeNode : BaseNode
{
public List<BaseNode> childs = new List<BaseNode>();
}
And this flat dto:
class NodeDto
{
public string name;
public List<NodeDto> childs;
}
(note how all derived types are represented by one dto class)
I use auto mapper to do a conversion:
Mapper.CreateMap<BaseNode, NodeDto>()
.Include<CompositeNode, NodeDto>()
.ForMember(s => s.childs, prop => prop.Ignore());
Mapper.CreateMap<CompositeNode, NodeDto>();
Mapper.AssertConfigurationIsValid();
var root = new CompositeNode() { name = "root" };
var child = new CompositeNode {name = "child"};
var child2 = new CompositeNode { name = "child2" };
root.childs.Add(child);
child.childs.Add(child2);
var rootDto = Mapper.Map<CompositeNode, NodeDto>(root);
However the below is always null instead of having the child list:
rootDto.childs[0].childs
(i.e. only first level child is mapped correctly)
If I remove the prop.Ignore part I get an assert error that the childs property is not mapped.
What am I doing wrong?
This is old, but came across it looking for something else... You're telling it to ignore the childs field. AutoMapper is doing what it was told to do.
.ForMember(s => s.childs, prop => prop.Ignore());
You don't have properties in your classes public string Name {get;set;}, you have public Fields, I think that's the problem
also in order to map this classes you only need to create 2 simple maps
Mapper.CreateMap<CompositeNode, NodeDto>();
Mapper.CreateMap<BaseNode, NodeDto>()
.ForMember(s => s.childs, prop => prop.Ignore());;

Categories