C# convert object in a list to another object - c#

Is it possible to assign list of objects to another list of objects that takes it as a constructor?
Eg.
public class PersonORM{
public PersonORM(Person p){ /* convert */ }
public int PersonId { get; set; }
/* Other properties here */
}
public class Person{
public int PersonId { get; set; }
/* Other properties here */
}
How do I convert Person to PersonORM using the constructor when they are in a list like this:
List<Person> people = getPeople();
List<PersonORM> peopleOrm = new List<Person>(people); // Is something like this possoble?

It is not possible to do that with the syntax you have as the constructor of List<T> does not support it.
If you can use linq (depending on which version of .Net you are targeting), you can do this:
List<PersonORM> personOrm = people.Select(p => new PersonORM(p)).ToList();
This uses the Select operator to perform the conversion from each item in the original list.

It can be done using LINQ:
List<PersonORM> peopleOrm = new List<Person>(people.Select(p => new PersonORM(p)));

Related

How to create at runtime, from an enum value, a List of subclass, and get the closed generic type relevant to the subclass, as a List of base class?

I'm actually trying to solve a problem with List in C#.
Here are my classes:
public class A {
public int ID { get; set; }
public string tag { get; set; }
}
public class B1 : A {
public int info { get; set; }
}
public class B2 : A {
public C info { get; set; }
}
public class C {
...
}
I would like to have a function like that:
public List<A> function(typeEnum t)
To be able to return an object instance of type List<B1> or List<B2> and so on, depending on the requested typeEnum, as a List<A>.
My problem is the different type of info in B1 and B2 classes.
Although your question is unclear (hence the comments), what you might be searching for is a LINQ extension.
var list_of_a = new List<A>{ new A(), new B1(), new B1(), new B2(), new C() };
var list_of_b = list_of_a.OfType<B1>();
where list_of_b only contains the elements that are of B1.
You could have a switch-case to do the OfType for you based on the typeEnum:
public List<A> function(typeEnum t, List<A> listToFilter)
{
switch (t)
{
case typeEnum.B1:
return listToFilter.OfType<B1>().ToList();
case typeEnum.B2:
return listToFilter.OfType<B2>().ToList();
default:
throw new NotImplementedException("Please implement " + t);
}
}
Or you can use a Linq Where function to filter.
If your typeEnum values match the name of the type you are filtering by, you could do something like:
public List<A> function(typeEnum t, List<A> listToFilter)
{
return listToFilter.Where(item => item.GetType().Name == t.ToString()).ToList();
}
In both cases, you'll need to cast the items in the returned list to have access to the 'info' property as they'll be returned as 'A' objects, but they are still instances of the type you filtered on.

How to access the object's specific properties from a list of objects sharing the same interface

I have an application where i have say 10 objects of different types. I wish to have them in same list and iterate through them on many occasions. I cant push them into one list because they are of different types. So i created an interface and created a property that all objects share. Now i have the list of objects and type of the list is the "interface". When i iterate through the object, i can't access the specific properties of the object because the compiler will only know at runtime what object it is. So if i try to code Object_A.Name, visual studio will show error because it doesn't know they type of object. I can obviously do an if else or something similar to find the type of object and cast it, but i want to know of there is a better way, or if this whole approach of having an interface is wrong and if i should have begun in a different direction.
In the code below, i want to get the Devname, which i can't because its not part of the interface, but belongs to every object. I could make it part of the interface, but every now and then i may need to get a specific property. hence wanting to know if there is a way to do it.
foreach (ICommonDeviceInterface device in Form1.deviceList)
{
if (device.DevName.Equals(partnername))
{
return device.Port[portNo].PortRef;
}
}
One way you could do this is by using reflection to try to get the property value of a named property from an object, using a helper method like:
public static object GetPropValue(object src, string propName)
{
return src?.GetType().GetProperty(propName)?.GetValue(src, null);
}
Credit for above code goes to: Get property value from string using reflection in C#
This requires no checking types or casting, it just returns the value of the property, or null if it doesn't contain the property.
In use it might look like:
private static void Main()
{
// Add three different types, which all implement the same interface, to our list
var devices = new List<ICommonDeviceInterface>
{
new DeviceA {DevName = "CompanyA", Id = 1},
new DeviceB {DevName = "CompanyB", Id = 2},
new DeviceC {Id = 3},
};
var partnerName = "CompanyB";
foreach (var device in devices)
{
// Try to get the "DevName" property for this object
var devName = GetPropValue(device, "DevName");
// See if the devName matches the partner name
if (partnerName.Equals(devName))
{
Console.WriteLine($"Found a match with Id: {device.Id}");
}
}
}
Classes used for the sample above:
interface ICommonDeviceInterface
{
int Id { get; set; }
}
class DeviceA : ICommonDeviceInterface
{
public int Id { get; set; }
public string DevName { get; set; }
}
class DeviceB : ICommonDeviceInterface
{
public int Id { get; set; }
public string DevName { get; set; }
}
class DeviceC : ICommonDeviceInterface
{
public int Id { get; set; }
}
Use "as" and "is" to know what type of interface
public class A : ICommonDeviceInterface
{
public int AMember;
}
public class B :ICommonDeviceInterface
{
public int BMember;
}
foreach (ICommonDeviceInterface device in Form1.deviceList)
{
if(device is A)
{
A a = device as A;
a.AMember = 100;
}
else if(device is B)
{
B b = device as B;
b.BMember = 123;
}
}

How add dynamically a list form one object to another?

I have a class that contains a list. I want to copy that list to another object that contains the same type and amount of attributes.
List<CinemaUnitSchema> cinemaUnitSchemas = new List<CinemaUnitSchema>();
foreach (CinemaUnit cinemaUnits in scenario.CinemaUnits)
{
cinemaUnitSchemas.Add(new CinemaUnitSchema
{
Name = cinemaUnits.Name,
AttendantPoints = cinemaUnits.AttendantPoints,
ShowPoints = cinemaUnits.ShowPoints
});
}
scenarioSchema.CinemaUnits.AddRange(CinemaUnitSchemas);
However, I'm receiving an error in this line of code;
AttendantPoints = cinemaUnits.AttendantPoints
The error I'm receiving is:
"Cannot implicitly convert type 'System.Collections.Generic.List < MyApp.Models.AttendantPoint >' to 'System.Collections.Generic.List < MyApp.Schemas.AttendantPointSchema >'."
Class of CinemaUnit is:
public class CinemaUnit
{
public string Name { get; set; }
public List<AttendantPoint> AttendantPoints { get; set; }
public bool ShowPoints { get; set; }
}
The Class of CinemaUnitSchema is:
public class CinemaUnitSchema
{
public string Name { get; set; }
public List<AttendantPoint> AttendantPoints { get; set; }
public bool ShowPoints { get; set; }
}
Solution Intended
Add in each iteration the respective list to the new object.
Thanks,
You can write a Copy method that makes a shallow copy using reflection.
void Copy(object from, object to)
{
var dict = to.GetType().GetProperties().ToDictionary(p => p.Name, p => p);
foreach(var p in from.GetType().GetProperties())
{
dict[p.Name].SetValue(to, p.GetValue(from,null), null);
}
}
What you actually need it's a way to convert AttendantPoint to AttendantPointSchema.
Solution 1: You can use AutoMapper framework to do it.
Solution 2: You can write generic converter like #Eser suggested.
Solution 3: You can crate converter manually for each class using extension methods, implicit or explicit operators or just write helper class with static functions.
Not sure if this is the problem, but it is probably a good bet that it is.
You are using a foreach statement with the camel case cinemaUnits but when you are trying to copy the fields you are using the title case CinemaUnits instead of the variable with camel case.

cannot convert error when trying to assign List<T> to List<U> where U is T's interface

here is code illustration
interface IObjectA
{
int Id { get; }
string Name { get; }
}
class ObjectA : IObjectA
{
public int Id { get; set; }
public string Name { get; set; }
public ObjectA(int id, string name)
{
Id = id;
Name = name;
}
}
There are two ways for me to generate List<IObjectA> from some other objects
First one is using forloop:
IList<IObjectA> list = new List<IObjectA>();
foreach(var item in someList)
{
list.Add(new ObjectA(item.Id, item.Name));
}
This works perfectly fine.
Then I tried with linq
IList<IObjectA> list = someList.Select(c => new ObjectA(c.Id, c.Name)).ToList();
The compiler will throw me a error basically saying cannot convert ObjectA to IObjectA
To make it work, i have to add
IList<IObjectA> list = someList.Select(c => new ObjectA(c.Id, c.Name)).Cast<IObjectA>().ToList();
Can some one explain why the compile would complain?
Thanks in advance!
The problem is that the linq expressions result in a List<ObjectA>. If you can treat this result as a List<IObjectA>, the compiler might let you add hypothetical OtherObjectA objects to the list, which would blow up on you if you ever tried to cast back to the original List<ObjectA> type, which should be allowed.
To get around this, you can .Cast() the elements before calling .ToList() to get a list of the correct type:
IList<IObjectA> list = someList.Select(c => new ObjectA(c.Id, c.Name)).Cast<IObjectA>().ToList();
You could also use the var keyword:
var list = someList.Select(c => new ObjectA(c.Id, c.Name)).ToList();
But this will still result in a List<ObjectA> and I suspect you need the List<IObjectA> for code further on.

Adding custom value in a LINQ join

I have two lists with me:
FXCashFlow [contains - amount, paymentdate, TradeId, Currency]
FXTrades [Contains - TradePreferences, TradeId]
What I need to have in the return class is:
Return Object [Type, amount, paymentdate, TradeId, Currency, TradePreference]
Where Type = "Fx", as the data is fetched from Fx class.
For Return Object, I am using a LINQ JOIN like this:
var list = _fxCashflow.GetAll().Join(_fxTrade.GetAll(),
outerKey => outerKey.TradeId,
innerKey => innerKey.TradeId,
(CashFlow, Trade) => new
{
//"Fx", <- This line gives error
CashFlow.TradeId,
Trade.TradeReference,
CashFlow.PaymentAmount,
CashFlow.CurrencyCode,
CashFlow.PaymentDate,
CashFlow.CashflowTypeCode
}
);
I need to insert "Fx", because this data will be concatenated to a class where this "Fx" will identify the records returning from cashflow class.
How can I insert a custom value in this returning object? Or if there's any other way to do this?
Much Appreciated!!
Try to insert it like this instead:
(CashFlow, Trade) => new
{
Type = "Fx",
CashFlow.TradeId,
Trade.TradeReference,
CashFlow.PaymentAmount,
CashFlow.CurrencyCode,
CashFlow.PaymentDate,
CashFlow.CashflowTypeCode
}
Wouldn't it make more sense to introduce an actual Fx class rather than using a string identifier?
public class Fx
{
public int TradeId { get; set; }
public string TradeRef { get; set; }
public decimal PaymentAmount { get; set; }
...
}
(CashFlow, Trade) => new Fx
{
TradeId = CashFlow.TradeId,
TradeRef = Trade.TradeReference,
PaymentAmount = CashFlow.PaymentAmount,
...
}
You can store this information in enum and use it inside your anonymous object or you can define a new property for the anonymous object.

Categories