We need that if the member doesn't exist on source but it exists in the destination, to have the destination member initialized. Currently we get nulls unless we manually initialize every single of the 15 members with:
List<string> Property = new List<string>();
This is our service
public MappingService()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Car, Bike>();
});
_mapper = config.CreateMapper();
}
public Bike MapToBike(Car car)
{
return _mapper.Map<Car, Bike >(car);
}
You probably should not rely on AutoMapper initializing your collections. Having null as property value is a valid case after all.
That said, although there is no standard way to do that, you can devise something that might work. For example, as mentioned, you can use .AfterMap() to populate all null collections with empty ones. Here is an extension method to do so:
/// <summary>
/// Populates all properties of standard collection types with empty collections
/// </summary>
public static IMappingExpression<TSrc, TDest> InitializeNullCollectionProps<TSrc, TDest>(this IMappingExpression<TSrc, TDest> map)
{
return map.AfterMap((src, dest) =>
{
var destType = typeof(TDest);
// find all applicable properties
var collectionProps = destType.GetProperties(BindingFlags.Public)
.Where(propInfo =>
{
if (!propInfo.CanRead)
{
return false;
}
// check if there is public setter
if (propInfo.GetSetMethod() == null)
{
return false;
}
var propertyType = propInfo.PropertyType;
// it can be Array, List, HashSet, ObservableCollection, etc
var isCollection = !propertyType.IsAssignableFrom(typeof(IList));
if (!isCollection)
{
return false;
}
var haveParameterlessCtor =
propertyType.GetConstructors().Any(ctr => !ctr.GetParameters().Any());
if (!haveParameterlessCtor)
{
return false;
}
return true;
})
.ToList();
// assign empty collections to applicable properties
foreach (var propInfo in collectionProps)
{
var value = propInfo.GetValue(dest);
if (value == null)
{
propInfo.SetValue(dest, Activator.CreateInstance(propInfo.GetType()));
}
}
});
}
It's usage will simply be:
Mapper.CreateMap<Src,Dest>()
// some mappings
.InitializeNullCollectionProps()
// some mappings
But I don't think there is a way to accurately determine if the member was already mapped to null from source, so it will have empty collection value anyway.
Related
I have the following class to create objects from a delimited line:
public class Mapper<T>
{
public T Map(string line, char delimiter)
{
if(String.IsNullOrEmpty(line))
throw new ArgumentNullException(nameof(line));
if (Char.IsWhiteSpace(delimiter))
throw new ArgumentException(nameof(delimiter));
var splitString = line.Split(delimiter);
var properties = typeof(T).GetProperties();
if(properties.Count() != splitString.Count())
throw new InvalidOperationException($"Row has {splitString.Count()} columns but object has {properties.Count()}.");
var obj = Activator.CreateInstance<T>();
for (var i = 0; i < splitString.Count(); i++)
{
var prop = properties[i];
var propType = prop.PropertyType;
var valType = Convert.ChangeType(splitString[i], propType);
prop.SetValue(obj, valType);
}
return (T)obj;
}
}
If I call the map method with a delimited string it will populate all of the properties on the object with the delimited values from the line.
However when I call this from the following:
public class CsvStreamReader<T>
{
private readonly Mapper<T> _mapper;
public CsvStreamReader(Mapper<T> mapper)
{
_mapper = mapper;
}
public IEnumerable<T> ReadCsvFile(string filePath, bool hasHeader)
{
if(hasHeader)
return File.ReadAllLines(filePath)
.Skip(1)
.Select(x => _mapper.Map(x, ','));
return File.ReadAllLines(filePath)
.Select(x => _mapper.Map(x, ','));
}
}
It will return a list of T but all of the properties will be null and won't have been set.
Update: Just realised my class wasn't a class but was actually a struct.
In order to make your Mapper<T> work when T is a value type, you need to set its properties while boxed as an object. Create your obj as an object using the the non-generic Activator.CreateInstance(typeof(T)), set its properties using reflection, then finally cast the it to the required type when returning it:
public class Mapper<T>
{
readonly List<PropertyInfo> properties = typeof(T).GetProperties().OrderBy(p => p.Name).ToList();
public T Map(string line, char delimiter)
{
if (String.IsNullOrEmpty(line))
throw new ArgumentNullException("line");
if (Char.IsWhiteSpace(delimiter))
throw new ArgumentException("delimiter");
var splitString = line.Split(delimiter);
if (properties.Count() != splitString.Count())
throw new InvalidOperationException(string.Format("Row has {0} columns but object has {1}", splitString.Count(), properties.Count()));
// Create as a reference (boxed if a value type).
object obj = Activator.CreateInstance(typeof(T));
// Set the property values on the object reference.
for (var i = 0; i < splitString.Count(); i++)
{
var prop = properties[i];
var propType = prop.PropertyType;
var valType = Convert.ChangeType(splitString[i], propType);
prop.SetValue(obj, valType);
}
// Cast to the return type unboxing if required.
return (T)obj;
}
}
Sample fiddle.
Note that your code should not depend on the order of properties returned by Type.GetProperties(). From the docs:
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
Thus I modified your code to order by name. You might choose to select another strategy such as using data member order for data contract types.
Finally, you might want to reconsider your design of using mutable structs, see Why are mutable structs “evil”? for some reasons why. To restrict your Mapper<T> to work only for reference types, you can add the following where constraint:
public class Mapper<T> where T : class
{
}
I have a generic list. I have to filter the list based on the value of the property of list item. Item type is not known until runtime.
I have to find the item type by reflection and then need to filter.
Please help me by any idea or example
Thanks.
I Hope this help
pass any list, and specify a property name, and a filter method
private IList FilterList(IList list, string propName, Predicate<object> filterMethod) {
var result = new List<object>();
foreach (var item in list) {
var value = item.GetType().GetProperty(propName).GetValue(item);
if (filterMethod(value)) {
result.Add(item);
}
}
return result;
}
Example :
var result = FilterList(list, "Age", age => (int)age >= 18);
you can develop it and make it fully dynamic
If the list is generic you should know at least a base type at compile time.
If the base type contains the property - just use it.
If only some of the subtypes(ideally one) contain the property you're interested in you can do a cast on the list and then use your property.
list.Cast<Derived>().Select(i => i.Property == "val");
If that is not ok(say the type of the list has many derived types that contain the property and others that do not), you can use dynamic with a try/catch block.
list.Select(i => {
try
{
dynamic item = i;
return item.Prop == "value";
}
catch(RuntimeBinderException) //this type doesn't contain the property
{
return false;
}
});
Try this. It can determine whether a List is a list of some specified type. Based on that you should be able to filter for any specific type.
public class TypeA
{ }
public class TypeB
{ }
public class GenericFilter
{
public bool IsOfType<T>(IEnumerable<dynamic> objectToInspect)
{
var genericType = objectToInspect.GetType().GenericTypeArguments[0];
return genericType == typeof(T);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void IdentifiesExpectedType()
{
var classToInspect = new List<TypeA>();
var filter = new GenericFilter();
Assert.IsTrue(filter.IsOfType<TypeA>(classToInspect));
}
[TestMethod]
public void RejectsNonMatchingType()
{
var classToInspect = new List<TypeA>();
var filter = new GenericFilter();
Assert.IsFalse(filter.IsOfType<TypeB>(classToInspect));
}
}
This works just as well:
public bool IsOfType<T>(IEnumerable<dynamic> listToFilter)
{
return (listToFilter as IEnumerable<T>) != null;
}
This will take a list of lists and group them into a Dictionary<Type, List<List<dynamic>> where all of the lists for each key are of that type. That way you can select lists of type T just by retrieving them from the dictionary.
public Dictionary<Type, List<List<dynamic>>> GroupListsByType(List<List<dynamic>> lists)
{
var types = lists.Select(list => list.GetType().GenericTypeArguments[0]).Distinct().ToList();
var grouped = new Dictionary<Type, List<List<dynamic>>>();
types.ForEach(type =>
{
grouped.Add(type, new List<List<dynamic>>());
grouped[type].AddRange(lists.Where(list=>list.GetType().GenericTypeArguments[0] == type));
});
return grouped;
}
(I'm not questioning the "why." I don't know if I would recommend this, but it's interesting to write.)
In a Dapper ORM application, I want to assign one object to another, or all data members at once. Like this:
public class TableA
{
public int UserId { get; set; }
public string ClientId { get; set; }
// ... more fields ...
public bool Query()
{
bool Ok = false;
try{
// Method A
TableA Rec = QueryResultRecords.First();
MyCopyRec(Rec, this); // ugly
// Method B
this = QueryResultRecords.First(); // avoids CopyRec, does not work
Ok = true;
}
catch(Exception e){
Ok = false;
}
return Ok;
}
}
With Method A you can assign the object from .First() directly to a new object of class TableA, and need a custom method MyCopyRec to get the data in the data members of the same class.
However, with Method B you cannot assign the same object directly to this.
Or is there another way to do this?
You cannot assign a object to "this" if "this" is a reference type, e.g. a class. "this" is a pointer to the current class instance.
This would only work if this is a value type, e.g. a struct.
You can only assign values to properties of "this" (which is what probably happens in the (CopyRec method), like:
var result = QueryResultRecords.First();
this.UserId = result.UserId;
/// <summary>
/// Extension for 'Object' that copies the properties to a destination object.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public static void CopyProperties(this object source, object destination)
{
// If any this null throw an exception
if (source == null || destination == null)
throw new ArgumentException("Source or/and Destination Objects are null");
// Getting the Types of the objects
Type typeDest = destination.GetType();
Type typeSrc = source.GetType();
// Iterate the Properties of the source instance and
// populate them from their desination counterparts
PropertyInfo[] srcProps = typeSrc.GetProperties();
foreach (PropertyInfo srcProp in srcProps)
{
if (!srcProp.CanRead)
{
continue;
}
PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name);
if (targetProperty == null)
{
continue;
}
if (!targetProperty.CanWrite)
{
continue;
}
if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
{
continue;
}
if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
{
continue;
}
// Passed all tests, lets set the value
targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
}
}
Here's that method I talked about in the comments above.
Also refer to this link: Apply properties values from one object to another of the same type automatically?
This is a simple example on how I update a value in the database:
var context = new dbEntities();
var car = context.CarTable.Where(p => p.id == id).FirstOrDefault();
car.Make = "Volvo";
context.SaveChanges();
However, what I need to do now is to get the property by name instead. So this is what I in theory would like to do:
var context = new dbEntities();
var car = context.CarTable.Where(p => p.id == id).FirstOrDefault();
**car["Make"] = "Volvo";**
context.SaveChanges();
Is this possible in EF?
I wouldn't use reflection since that would be slow.
You can use expression trees, especially if you cache the expressions. Check this link for an article about it. I would write a wrapper around the code in the article which takes an object and a propertyname (string), creates/caches the func using the code in the article (or retrieves it from the cache), and executes the func.
The main question is really why do you need this?
The best way is still car.Make = "Volvo";.
If string-name is strongly needed, you can use Reflection:
var property = typeof (Car).GetProperty("Make");
property.SetValue(car, "BMW", null);
Here are 2 drawbacks:
Slow.
Compiler cannot check the string.
The other way - you can use indexer and switch:
public class Car
{
public string Make { get; set; }
public string this[String name]
{
set
{
switch (name)
{
case "Make":
Make = value;
break;
...
}
}
}
}
And then just car["Make"] = "Volvo";
It's faster, but a typ-problem occurs: you have to parse strings or operate with objects.
public class Car
{
public string Make { get; set; }
public object this[string name]
{
get
{
var property = this.GetType().GetProperties().FirstOrDefault(p => p.Name.Equals(name));
if (property != null)
{
return property.GetValue(this, null);
}
return null;
}
set
{
var property = this.GetType().GetProperties().FirstOrDefault(p => p.Name.Equals(name));
if (property != null)
{
property.SetValue(this, value, null);
}
}
}
}
I have an object model MyObject with various properties. At one point, I have two instances of these MyObject: instance A and instance B. I'd like to copy and replace the properties in instance A with those of instance B if instance B has non-null values.
If I only had 1 class with 3 properties, no problem, I could easily hard code it (which is what I started doing). But I actually have 12 different object models with about 10 properties each.
What's good way to do this?
Update
Use AutoMapper instead if you need to invoke this method a lot. Automapper builds dynamic methods using Reflection.Emit and will be much faster than reflection.'
You could copy the values of the properties using reflection:
public void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
I've made it generic to ensure type safety. If you want to include private properties you should use an override of Type.GetProperties(), specifying binding flags.
I have tried what's described by Merge Two Objects into an Anonymous Type by Kyle Finley and it is working perfectly.
With the TypeMerger, the merging is as simple as
var obj1 = new {foo = "foo"};
var obj2 = new {bar = "bar"};
var mergedObject = TypeMerger.MergeTypes(obj1 , obj2 );
That's it! You've got the merged object. Apart from that, there is a provision to ignore specific properties too. You can use the same thing for MVC3 as well.
You can do it using reflection, but as someone stated, it'll have a performance penalty.
Since you're working with an expected class design, you can achieve the same goal by using an extension method like so:
public static class MyClassExtensions
{
public static void Merge(this MyClass instanceA, MyClass instanceB)
{
if(instanceA != null && instanceB != null)
{
if(instanceB.Prop1 != null)
{
instanceA.Prop1 = instanceB.Prop1;
}
if(instanceB.PropN != null)
{
instanceA.PropN = instanceB.PropN;
}
}
}
And later, somewhere in your code:
someInstanceOfMyClass.Merge(someOtherInstanceOfMyClass);
At the end of the day you've centralized this operation in an extension method and if you add or remove a property of your class, you only need to modify extension method's implementation and you'll get everything done.
you can use this package:XASoft
use foo.Merger(bar) method
to combine 2 object to a dynamic object
just like this
var objA = new { a = 1, b = 2, c = 3 };
var newObj = objA.Merger(new { a = "Hey", d = 4, e = 5 });
newObj.e = "There";
newObj.f = 6;
Console.WriteLine(JsonConvert.SerializeObject(newObj));
even if object list works fine too!
private class TestClass
{
public int X { get; set; }
public int Y { get; set; }
}
static void Main(string[] args)
{
var list = new List<TestClass> {
new TestClass{ X=1,Y=2},
new TestClass{ X=3,Y=4}
};
Console.WriteLine(JsonConvert.SerializeObject(list.ListMerger(i => new
{ X = "null value", Z = i.X == 1 ? 0 : 1 })));
}
oops,looks like javascript language...
btw,source code click here
I've created a method similar to some answers above, but it returns a new object merged between 2 objects, and will only merge the second objects value if the first objects value is null.
public T MergeObjects<T>(T primary, T secondary)
{
T obj = (T)Activator.CreateInstance(typeof(T));
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(primary, null);
if (value != null)
prop.SetValue(obj, value, null);
else
{
value = prop.GetValue(secondary, null);
if (value != null)
prop.SetValue(obj, value, null);
}
}
return obj;
}
I've written my own class for this purpose: ObjectMerger.
Basically it uses reflections (and may be slow because of that). It also contains more features e.g. parsing objects for cyclic references and merge them too. My ObjectMerger also contains mechanism to handle more complex classes like Delegate or MemberInfo. Those will be copied completely, other objects in the class are recursively merged.
The Syntax is like:
var initialInstance = new MyObjectBase(); // Initialize first object
var properInstance = new MyObjectWithAlgorithms(); // Initialize second object
var result = ObjectMerger.MergeObjects(properInstance, initialInstance); // Merge Objects into type of "properInstance"
I'm sorry to say that it is NOT FOR USE AS IS, because some external libraries are missing in the repository at the moment due to limitations in my company, but they can easily be rewritten. I hope a can add them in future.
This is the same as #Bas Answer but for Merging 2 Object lists
public class Copycontents
{
public static void Work<T>(IList<T> targetList, IList<T> sourceList, Func<T, int> selector)
{
var matchingPrimaryKey = targetList.Select(x => selector(x)).ToList();
foreach (var thismatchingPrimaryKey in matchingPrimaryKey)
{
CopyValues<T>(targetList.Single(x => selector(x) == thismatchingPrimaryKey),
sourceList.Single(x => selector(x) == thismatchingPrimaryKey));
}
}
private static void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
}