Is there a way to convert a nested object to an object. For example lets say I have an object of class ABC as shown below.
class ABC
{
int id {get;set;}
XYZ myobj {get;set}
}
class XYZ
{
string name {get;set;}
string addr {get;set;}
}
Is there any way to convert this ABC class object to UVW class object like below.
class UVW
{
int id {get;set;}
string name {get;set;}
string addr {get;set;}
}
If you are looking for a provision in C# to convert an object of ABC to an object of UVW, then am afraid there is no such thing.
If you want, you could just write your own conversion logic though (after making the properties public):
private UVW ConvertToUVW(ABC abc)
{
if (abc == null)
{
return null;
}
var uvw = new UVW();
uvw.id = abc.id;
uvw.name = abc.myobj?.name;
uvw.addr= abc.myobj?.addr;
return uvw;
}
You can use Automapper's automatic flattening for this. It works by naming convention, to map a Foo.Bar in the source to a FooBar destination, or by configuration where the first configured match wins in case of conflicts.
Given these source types:
class SourceRoot
{
public int Id { get; set; }
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
class Foo
{
public string Name { get; set; }
public string Addr { get; set; }
}
class Bar
{
public string Name { get; set; }
public string Addr { get; set; }
}
Which is to be mapped to this target:
class TargetFlattened
{
public int Id { get; set; }
public string Name { get; set; }
public string Addr { get; set; }
public string BarAddr { get; set; }
}
You can automap from source to flattened target like this:
var source = new SourceRoot
{
Id = 42,
Foo = new Foo
{
Addr = "FooAddr",
Name = "FooName"
},
Bar = new Bar
{
Addr = "BarAddr",
Name = "BarName"
}
};
var configuration = new MapperConfiguration(cfg => {
// First, map complex property types
cfg.CreateMap<Foo, TargetFlattened>();
cfg.CreateMap<Bar, TargetFlattened>();
// Then the root type
cfg.CreateMap<SourceRoot, TargetFlattened>()
.IncludeMembers(a => a.Foo, a => a.Bar)
.ReverseMap();
});
var target = configuration.CreateMapper().Map<TargetFlattened>(source);
Note that this will yield:
Id: 42
Addr: FooAddr
BarAddr: BarAddr
Name: FooName
The IncludeMembers() configuration will map members that don't adhere to the naming convention (Name instead of FooName for Foo.Name).
Meaning, if you have multiple complex properties with a Name property, you'll get the first included member's Name property mapped into your target's Name.
If you swap them to .IncludeMembers(a => a.Bar, a => a.Foo), your Name will be "BarName".
Related
I have an object ObjA of type as following
class TypeA A
{
string fied ID{get; set;}
public List<TypeA> children{get; set;}
}
I want to copy this ObjA to ObjB which is as following
class TypeB B
{
string fied ID{get; set;}
public List<TypeB> children{get; set;}
}
If you want to copy an object values from one object to another, you can have a utility function that handles the creation and assignment of one object type to another.
static TypeB Copy(TypeA obj)
{
TypeB copiedObj = new TypeB();
// Assign values from obj to copiedObj
// copiedObj.Id = obj.Id;
return copiedObj;
}
It is hard to help you because it is unclear what you try to achieve with this.
But maybe an Interface is the best way to go for you.
public interface ITyp
{
string FieldID { get; set; }
List<ITyp> Children { get; set; }
}
public class TypA : ITyp
{
public string FieldID { get; set; }
public List<ITyp> Children { get; set; } = new List<ITyp>();
}
public class TypB : ITyp
{
public string FieldID { get; set; }
public List<ITyp> Children { get; set; } = new List<ITyp>();
}
With this, you can map TypA and TypB to the same object ITyp.
ITyp ityp = new TypA();
ityp = new TypB();
You can use the interface directly.
string ID = ityp.FieldID;
Or you can Convert it back to TypA or TypB.
TypA typaChild;
if (ityp.Children[0].GetType() == typeof(TypA)) typaChild = (TypA)ityp.Children[0];
Let say I have a base class and two derived classes.
public abstract class BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
public class Foo : BaseClass
{
[CustomAttr(Order = 2)]
public string Country { get; set; }
[CustomAttr(Order = 5)]
public decimal Amount { get; set; }
public string Other { get; set; }
}
public class Bar : BaseClass
{
[CustomAttr(Order = 3)]
public string Organization { get; set; }
[CustomAttr(Order = 1)]
public string Keywords { get; set; }
}
By default, the order of the properties is based on how they are declared in the class so if in the BaseClass since there is no [CustomAttr(Order = n) assume this is the correct order.
Now since in the two derived class, there is a defined custom attribute that will identify the property order the behavior should be sorted by:
Id
Country
Name
Description
Amount
Owner
DateAdded
Other
So what will happen those with CustomAttr[(Order = n)] should be placed to their property order and for those that do not have we assume they are in there proper order. This should also have a similar behavior if I use the Bar class.
The use case of this is I need to have the right order of the properties of the class in the List<T> to have the correct order of column in an excel file.
What I did is I have to add the CustomAttr[(Order = n)] to all of the properties to sort them however this is a tedious thing to do which require you to change the order of all properties if you try to change one of the property order.
Any way that I can achieve this?
You can use reflection to read the names of all of the properties of a class in the order they are declared. You can then elaborate this in your logic and sort the fields accordingly.
Try the following:
PropertyInfo[] propertyInfos = typeof(Bar).GetProperties();
foreach (var propInfo in propertyInfos)
Console.WriteLine(propInfo.Name);
This will write all of the properties in the Bar class (this is just an example, you can replace that by any of your classes), including the properties inherited from its superclass (BaseClass). Expected output:
Organization
Keywords
Id
Name
Description
Owner
DateAdded
Notice though that this method lists the properties from the class first, and then goes up in the hierarchy listing each superclass (this is why Bar's members are being listed before BaseClass's members). You can elaborate the code a little bit more to change the order according to your needs.
The following (non-optimized) code first creates a list of all of the given class' hierarchy, starting from the base class towards the given T class. After that, it iterates over each of the classes, discovering only the properties defined in each class (I'm passing the GetProperties() method a parameter stating that I just want the properties that are public, instance/non-static, and declared on the specific class I am currently consulting).
private static void ListAllOrderedPropertiesOfType(Type targetType)
{
// Generate a list containing the whole hierarchy of classes, from the base type to the type T
var typesList = new List<Type>();
for (Type t = targetType; t != typeof(Object); t = t.BaseType)
typesList.Insert(0, t);
// Iterate from the base type to type T, printing the properties defined for each of the types
foreach (Type t in typesList)
{
PropertyInfo[] propertyInfos = t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var propInfo in propertyInfos)
Console.WriteLine(propInfo.Name);
}
}
So if you wanted to know all of the properties for type Bar, ordered from the topmost base class towards the Bar class, you could call this method like that:
ListAllOrderedPropertiesOfType(typeof(Bar));
Expected output would be the properties in the following order:
Id
Name
Description
Owner
DateAdded
Organization
Keywords
With that you know the fields' declaration order and their custom orders (through your CustomAttr attribute). You can now implement a sort method to order the fields according to their declaration orders and CustomAttr orders, according to your needs.
But I guess this is a little beyond the scope of my answer (which intends to show you how to get the order of declaration of properties, from a base class towards any given specific class).
I created a generic solution by reading your attribute and creating a comparer what will compare in the order of your attribute order. in the contructor of the comparer I am reading over reflection your attributes. While comparing I take one property after the other and when equal (zero), I go to the next.
The logic works also with inheritance, so even on the base class you can have CustomAttr.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomAttr : Attribute
{
public CustomAttr():base()
{}
public CustomAttr(int Order)
{
this.Order = Order;
}
public int Order {get ; set ; }
}
public abstract class BaseClass
{
public int Id { get; set; }
[CustomAttr(Order = 20)]
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
public class Foo : BaseClass
{
[CustomAttr(Order = 2)]
public string Country { get; set; }
[CustomAttr(Order = 5)]
public decimal Amount { get; set; }
public string Other { get; set; }
}
public class Bar : BaseClass
{
[CustomAttr(Order = 3)]
public string Organization { get; set; }
[CustomAttr(Order = 1)]
public string Keywords { get; set; }
}
class app
{
static void Main()
{
List<Bar> listToOrder = new List<Bar>();
listToOrder.Add(new Bar() { Id = 5, Keywords = "Hello", Organization = "Arlando" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" , Name = "Deep"});
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta", Name = "Inherit" });
listToOrder.Add(new Bar() { Id = 1, Keywords = "Muppet", Organization = "Coke" });
listToOrder.Add(new Bar() { Id = 6, Keywords = "Grumpy", Organization = "Snow" });
listToOrder.Add(new Bar() { Id = 9, Keywords = "Johny", Organization = "White" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Bruno" });
listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" });
listToOrder.Add(new Bar() { Id = 7, Keywords = "Set", Organization = "Voltra" });
listToOrder.Add(new Bar() { Id = 45, Keywords = "Brr", Organization = "Elvis" });
listToOrder.Add(new Bar() { Id = 15, Keywords = "Tsss", Organization = "Marion" });
OrderComparer<Bar> myOrder = new OrderComparer<Bar>();
listToOrder.Sort(myOrder);
foreach (Bar oneBar in listToOrder)
{
Console.WriteLine(oneBar.Id + " " + oneBar.Keywords + " " + oneBar.Organization);
}
Console.ReadKey();
}
private class OrderComparer<T> : IComparer<T>
{
SortedList<int, PropertyInfo> sortOrder = new SortedList<int, PropertyInfo>();
public OrderComparer()
{
Type objType = typeof(T);
foreach (PropertyInfo oneProp in objType.GetProperties())
{
CustomAttr customOrder = (CustomAttr) oneProp.GetCustomAttribute(typeof(CustomAttr), true);
if (customOrder == null) continue;
sortOrder.Add(customOrder.Order, oneProp);
}
}
public int Compare(T x, T y)
{
Type objType = typeof(T);
int result = 0;
int i = 0;
while (result == 0 && i < sortOrder.Count)
{
result = ((IComparable)sortOrder.ElementAt(i).Value.GetValue(x)).CompareTo(sortOrder.ElementAt(i).Value.GetValue(y));
i++;
}
return result;
}
}
}
See this example for order using List with system.Linq
class Program
{
class test
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Owner { get; set; }
public DateTime DateAdded { get; set; }
}
static void Main(string[] args)
{
List<test> listOrder = new List<test>();
listOrder.Add(new test() { Id = 1, Name = "john", Description = "test", Owner = "test", DateAdded = DateTime.Now });
listOrder.Add(new test() { Id = 1, Name = "max", Description = "test1", Owner = "test1", DateAdded = DateTime.Now });
listOrder.Add(new test() { Id = 1, Name = "phil", Description = "test2", Owner = "test2", DateAdded = DateTime.Now });
List<test> sortbyName = listOrder.OrderBy(item => item.Name).ToList();
List<test> sortbyDescription = listOrder.OrderBy(item => item.Description).ToList();
List<test> sortbyOwner = listOrder.OrderBy(item => item.Owner).ToList();
}
}
I would like to build a Function where user could search if certain property from list contains value
Let say we will have List, and Company will be defined as a class with properties like :
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
Now - Ideally I would like to have function with this parameters
List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x."fieldToQueryOn".ToString().ToLower().Contains(query.ToLower())).ToList();
}
and call :
var variable = FilterCompanies(NotNullFilledUnfilteredList, "CompanyCity", "New York")
I tried to follow the tutorial at learn.microsoft.com and it's easy, but I don't have clue how to extend that solution with reflection on Type and use it in an expression tree.
You can use Type.GetProperty to find a property by name using reflection, and then use GetValue to retrieve the value:
List<Company> FilterCompanies(List<Company> list, string propertyName, string query)
{
var pi = typeof(Company).GetProperty(propertyName);
query = query.ToLower();
return list
.Where(x => pi.GetValue(x).ToString().ToLower().Contains(query))
.ToList();
}
You should probably add some error handling though in case someone uses a property that is invalid. For example, you could do (pi?.GetValue(x) ?? string.Empty).ToString().ToLower()… to be on the safe side.
I’ve also moved the query.ToLower() out of the lambda expression to make sure it only runs once. You can also try other case-insensitive ways to check whether query is a substring of the value to avoid having to convert any string. Check out the question “Case insensitive 'Contains(string)'” for more information.
Btw. if you are generally interested in running dynamic queries, you should take a look at dynamic LINQ.
Generics and lambda:
namespace WhereTest
{
class Program
{
static void Main(string[] args)
{
var companies = new[] { new Company { Id = 1, Name = "abc" }, new Company { Id = 2, CompanyAddress1 = "abc" } };
foreach (var company in FilterCompanies(companies, "abc", x => x.Name, x => x.CompanyCity))
{
Console.WriteLine(company.Id);
}
}
static List<Company> FilterCompanies(IEnumerable<Company> unfilteredList, string query, params Func<Company, string>[] properties)
{
return unfilteredList.Where(x => properties.Any(c => c.Invoke(x) == query)).ToList();
}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
}
Advantages: no reflection, strongly typed code.
You can use GetProperty combined with GetValue
List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
return unfilteredList
.Where(x => x.GetType.GetProperty(fieldToQueryOn).GetValue(x)
.ToString().ToLower().Contains(query.ToLower())).ToList();
}
OR: property accessors using string (same as javascript obj[property])
You can modify your class:
public class Company
{
// just add this code block to all your classes that would need to access
// your function
public object this[string propertyName]
{
get{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
and then you can change your function like this:
List<Company> FilterCompanies(List<Company> unfilteredList, string key, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x[key].ToString().ToLower().Contains(query.ToLower())).ToList();
}
Check this Demo
NOTE:
In order for your function to work, you need to add this code to your classes:
public object this[string propertyName]
{
get{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
Bonus: you can now retrieve values using myObject["someproperty"] and you can even set their values!
For performance reasons I am mapping a set of entities to a view creating a flat table (in a way transforming a TPT inheritance in a TPH). This is to be used only a specific method.
[view]
id
property1
property2
propertyN
complex_type_collection_property1
complex_type_collection_property2
complex_type_collection_propertyN
Is there a way to map the complex_type_collection_properties to a complex property on the materialized object?
e.g.
[Object]
id = [view].Id
property1 = [view].property1
property2 = [view].property2
propertyN = [view].propertyN
Collection = [{property1 = [view].complex_type_collection_property1, ...}, ...]
Thank you!
Ok I created example, I assume that you already have entity(fromDB variable at my code, lets imagine that it taken from DB) or entities retrieved from DB. Than you can cast each entity as shown below. Solution is comprehensive and little sophisticated. You should also specify type parameterNormalized<City> that corresponds to your complex type (if you will want to change complex type to another one there will not needed to do any changes at casting method). Also names of your complex properties(City1, City2, etc) must contain name of collection property(City), it is - some conventions. And I created BaseClass with shared properties, our two classes derrived from it (so you able to not copy fields from one class to another, instead you should place them into BaseClass). Also you can have the only one collection, i.e. property of type List<T>.
public class City
{
public string Name { get; set; }
public int Population { get; set; }
}
public class BaseClass
{
public int id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class POCO : BaseClass
{
public City City1 { get; set; }
public City City2 { get; set; }
public City City3 { get; set; }
}
public class Normalized<T> : BaseClass
{
public List<T> City { get; set; }
public static explicit operator Normalized<T>(POCO self)
{
if (self == null)
return null;
var normal = new Normalized<T>();
foreach (var prop in typeof(BaseClass).GetProperties())
prop.SetValue(normal, prop.GetValue(self));
var complexProp = typeof(Normalized<T>).GetProperties().Where(x => x.PropertyType.GetInterfaces().Any(y => y.Name == "ICollection")).First();
complexProp.SetValue(normal, new List<T>((typeof(POCO).GetProperties().Where(x => x.Name.Contains(complexProp.Name)).Select(x => (T)x.GetValue(self)).ToList())));
return normal;
}
}
public static void Main(string[] args)
{
var fromDB = new POCO
{
Age = 20,
id = 1,
Name = "Mike",
City1 = new City { Name = "Moscow", Population = 10 },
City2 = new City { Name = "London", Population = 20 },
City3 = null
};
var normal = (Normalized<City>)fromDB;
Console.WriteLine(normal.City.Select(x => x == null ? "EMPTY" : x.Name).Aggregate((a, b) => { return a + ", " + b; }));
}
I'm trying to use Automapper to map to objects, the issue is one of the objects I'm trying to map has a prefix 'Cust_' in front of all its properties and one doesn't. Is there a way to make this mapping.
For example say I have
class A
{
String FirstName { get; set; }
String LastName { get; set; }
}
class B
{
String Cust_FirstName { get; set; }
String Cust_LastName { get; set; }
}
Obviously this map won't work
AutoMapper.Mapper.CreateMap<A, B>();
b = AutoMapper.Mapper.Map<A, B>(a);
Mapper.Initialize(cfg =>
{
cfg.RecognizeDestinationPrefixes("Cust_");
cfg.CreateMap<A, B>();
});
A a = new A() {FirstName = "Cliff", LastName = "Mayson"};
B b = Mapper.Map<A, B>(a);
//b.Cust_FirstName is "Cliff"
//b.Cust_LastName is "Mayson"
Or alternatively:
Mapper.Configuration.RecognizeDestinationPrefixes("Cust_");
Mapper.CreateMap<A, B>();
...
B b = Mapper.Map<A, B>(a);
...
The documentation has an article on Recognizing pre/postfixes
Sometimes your source/destination properties will have common pre/postfixes that cause you to have to do a bunch of custom member mappings because the names don't match up. To address this, you can recognize pre/postfixes:
public class Source {
public int frmValue { get; set; }
public int frmValue2 { get; set; }
}
public class Dest {
public int Value { get; set; }
public int Value2 { get; set; }
}
Mapper.Initialize(cfg => {
cfg.RecognizePrefix("frm");
cfg.CreateMap<Source, Dest>();
});
Mapper.AssertConfigurationIsValid();
By default AutoMapper recognizes the prefix "Get", if you need to clear the prefix:
Mapper.Initialize(cfg => {
cfg.ClearPrefixes();
cfg.RecognizePrefixes("tmp");
});