Let's say we have a class
class ComplexCls
{
public int Fld1;
public string Fld2;
//could be more fields
}
class Cls
{
public int SomeField;
}
and then some code
class ComplexClsList: List<ComplexCls>;
ComplexClsList myComplexList;
// fill myComplexList
// same for Cls
class ClsList : List<Cls>;
ClsList myClsList;
We want to populate myClsList from myComplexList, something like (pseudocode):
foreach Complexitem in myComplexList
{
Cls ClsItem = new Cls();
ClsItem.SomeField = ComplexItem.Fld1;
}
The code to do this is easy and will be put in some method in myClsList. However I'd like to design this as generic as possible, for generic ComplexCls. Note that the exact ComplexCls is known at the moment of using this code, only the algorithm shd be generic.
I know it can be done using (direct) reflection but is there other solution? Let me know if the question is not clear enough. (probably isn't). [EDIT] Basically, what I need is this: having myClsList, I need to specify a DataSource (ComplexClsList) and a field from that DataSource (Fld1) that will be used to populate my SomeField
This is just a mapping, so use some simple LINQ:
ClsList myClsList = new ClsList();
myClsList.AddRange(
myComplexList.Select(Complexitem => new Cls { SomeField = Complexitem.Fld1 })
);
Okay, the easier version assuming we have a known target field on a class (I've written this as an extension method, no need to do
public IEnumerable<Cls> MapField<TSource>(IEnumerable<TSource> sourceList,
Func<TSource, int> sourceSelector)
{
return sourceList.Select(x => new Cls {SomeField = sourceSelector(x)});
}
Called this way
IEnumerable<Cls> result = MapField(myComplexList, x => x.Fld1);
Aside: Since your myComplexList
of type ComplexClsList
inherits from List
(which implements IEnumerable
this will work. The result isn't of type ClsList
that you wanted, but you could easily call .ToList()
on the result and provide a constructor on ClsList
that takes a List<Cls>
.
And the more complicated version for when we don't know the target field (or type)...
public IEnumerable<TResult> MapField<TSource, TResult, TMap>(
IEnumerable<TSource> sourceList,
Func<TSource, TMap> sourceSelector,
Func<TMap, TResult> resultCreator)
{
return sourceList.Select(x => resultCreator(sourceSelector(x)));
}
Not as pretty to call....
IEnumerable<Cls> result = MapField(
myComplexList,
source => source.Fld1,
valueToMap => new Cls() {SomeField = valueToMap});
Might be a better way, but it's not occurring to me at the moment.
Edit: Actually, you could combine the two Func
on the last one into a single one that takes a TSource
and creates and maps the necessary fields to TResult
, but I'm really not sure what you're gaining with that extra layer of abstraction...
You may want to reconsider extending List
classes in the first place. What does inheritance give you, in this case? I suspect that you'll be better off favoring composition over inheritance here. One possible approach would be:
// If you would say that a ComplexCls "is a" Cls, then maybe your inheritance
// relationship belongs here instead.
public class ComplexCls : Cls {
}
public class ClsList
{
public IReadOnlyCollection<Cls> Items {get;set;}
}
public class ComplexClsList
{
public IReadOnlyCollection<ComplexCls> Items {get;set;}
}
Then you can create a ClsClist easily.
ClsList basicList = new ClsList{Items = complexList.Items};
But you may want to take it a step farther and question why the ClsList
and ComplexClsList
classes exist at all. Why not simply pass around List
s directly. I mean, what's the difference between a ClsList
and a "List of Clses" ( List<Cls>
)?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.