Generic extension method for automapper - c#

public abstract class Entity : IEntity
{
[Key]
public virtual int Id { get; set; }
}
public class City:Entity
{
public string Code { get; set; }
}
public class BaseViewModel:IBaseViewModel
{
public int Id { get; set; }
}
public class CityModel:BaseViewModel
{
public string Code { get; set; }
}
my domain and view classes...
and
for mapping extension
public static TModel ToModel<TModel,TEntity>(this TEntity entity)
where TModel:IBaseViewModel where TEntity:IEntity
{
return Mapper.Map<TEntity, TModel>(entity);
}
and i am using like below
City city = GetCity(Id);
CityModel model = f.ToModel<CityModel, City>();
but its long
can i write it like below?
City city = GetCity(Id);
CityModel model = f.ToModel();
is that possible?

Instead of jumping through all of those hoops, why not just use:
public static TDestination ToModel<TDestination>(this object source)
{
return Mapper.Map<TDestination>(source);
}

No because the 1st generic argument can't be implicitly inferred.
I would do this
public static TModel ToModel<TModel>(this IEntity entity) where TModel:IBaseViewModel
{
return (TModel)Mapper.Map(entity, entity.GetType(), typeof(TModel));
}
Then the code is still shorted than it was:
var city = GetCity(Id);
var model = city.ToModel<CityModel>();

Put the extension method on IEntity as a member method. Then you have to pass only one type.

Related

Get existing instance of List<T>

I've inherited a bloated project that uses a huge class as an in-memory database:
public class Database
{
public class Parameter1
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter1Value> paramValues;
}
public class Parameter2
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter2Value> paramValues;
}
public class Parameter1Value
{
public string Value { get; set;}
public Parameter parameter { get; set;}
}
public class Parameter2Value
{
public int Value { get; set;}
public Parameter2 parameter { get; set;}
}
public List<Parameter1> parameter1List { get; set; }
public List<Parameter2> parameter2List { get; set; }
}
I am creating a generic method that creates instances of Parameter1 or Parameter2 (see below) and should add those to their respective lists, but I don't know how to use those types to get the parameter1List or parameter2List instances from my Database class. The Database class holds only one List<T> property for each defined type. Is this possible?
This is the generic method used to create instances:
public static Database Add<T>(this Database database, string code, string label) where T : new()
{
T itemToCreate = (T)Activator.CreateInstance(typeof(T));
itemToCreate.Code = code;
itemToCreate.Label = label;
var listForItem = database.GetList<T>; // This is the missing functionality
listForItem.Add(itemToCreate);
return database;
}
Here is a solution using interfaces and generic constraints.
Create an interface to represent a generic parameter class and add members to the interface as required:
public interface IParameter { ... }
And an interface to represent a list of parameters:
public interface IParameterList<TParameter> where TParameter : IParameter
{
List<TParameter> ParameterList { get; set; }
}
Have the Database and Parameter classes implement these new interfaces:
public class Parameter1 : IParameter
public class Parameter2 : IParameter
public class Database : IParameterList<Parameter1>, IParameterList<Parameter2>
{
List<Parameter1> IParameterList<Parameter1>.ParameterList { get => parameter1List; set => parameter1List = value; }
List<Parameter2> IParameterList<Parameter2>.ParameterList { get => parameter2List; set => parameter2List = value; }
...
}
Add a where TParameter : IParameter constraint to your generic Parameter factory function, and have the factory function require an argument of type IParameterList<TParameter> which is an instance of the Database class. This satisfies the compiler that the Database class owns a list of TParameter. Now we just do db.ParameterList.Add(r) to add our new parameter to the correct list.
public static TParameter CreateParameter<TParameter>(IParameterList<TParameter> db) where TParameter : IParameter, new()
{
var r = new TParameter(); // This is the generic function you mentioned. Do stuff here to create your Parameter class.
db.ParameterList.Add(r); // Add the newly created parameter to the correct list
return r;
}
Code dump (full working version after I picked up your edit which added the generic factory function):
public class Parameter1 : IParameter
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter1Value> paramValues;
}
public class Parameter2 : IParameter
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter2Value> paramValues;
}
public class Parameter1Value
{
public string Value { get; set; }
public Parameter parameter { get; set; }
}
public class Parameter2Value
{
public int Value { get; set; }
public Parameter2 parameter { get; set; }
}
public class Database : IParameterList<Parameter1>, IParameterList<Parameter2>
{
// Note: Setters for the List properties probably not needed here or in IParameterList as with the following code we instantiate them at class construction time and, in this MCVE at least, there are no further assignments
public List<Parameter1> parameter1List { get; set; } = new List<Parameter1>();
public List<Parameter2> parameter2List { get; set; } = new List<Parameter2>();
List<Parameter1> IParameterList<Parameter1>.ParameterList { get => parameter1List; set => parameter1List = value; }
List<Parameter2> IParameterList<Parameter2>.ParameterList { get => parameter2List; set => parameter2List = value; }
public static TParameter Add<TParameter>(IParameterList<TParameter> db, string code, string label) where TParameter : IParameter, new()
{
var itemToCreate = new TParameter();
itemToCreate.Code = code;
itemToCreate.Label = label;
db.ParameterList.Add(itemToCreate); // Add the newly created parameter to the correct list
return itemToCreate;
}
}
public interface IParameter
{
string Code { get; set; }
string Label { get; set; }
}
public interface IParameterList<TParameter> where TParameter : IParameter
{
List<TParameter> ParameterList { get; set; }
}
// Testing:
void Main()
{
var db = new Database();
Database.Add<Parameter1>(db, "hello", "hello2");
Database.Add<Parameter1>(db, "hello", "hello2");
Database.Add<Parameter2>(db, "hello", "hello2");
Console.WriteLine($"P1 count (should be 2): {db.parameter1List.Count()}; P2 count (should be 1): {db.parameter2List.Count}");
}
Output:
P1 count (should be 2): 2; P2 count (should be 1): 1
Here is a solution which acquires the target list using generics and reflection:
public static List<T> GetList<T>(this Database dataBase) where T : new()
{
return dataBase.GetType()
.GetProperties()
.Where(x => x.PropertyType == typeof(List<T>))
.Select(x => (List<T>)x.GetValue(dataBase))
.FirstOrDefault();
}
Credit: Michael Randall in the comments

Need solution regarding generic c# method

I am trying to make my method generic and I am stuck at a point and need your assistance. The code scenario is I have an abstract class say MyBaseAbs which contains common properties:
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
}
Now I have child classes:
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
}
and another child class:
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
}
Now I have to create a common method which needs to perform some operations on the basis of Mychild1 and Mychild2, so what I did is:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
}
so inside this method I need to write common code which does the mapping for SaveObject object according to the child object passed. How can I determine which object is passed and use properties accordingly.
One option would be to create a base Save function in your base class and make it virtual.
Then override the method in your child classes. This way when you call the Save method in your SaveOperation it should call the appropriate method from the correct child class.
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
public virtual void Save() { }
}
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
public override void Save() {
//Implementation for Mychild1
}
}
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
public override void Save() {
//Implementation for Mychild2
}
}
If you can't modify your business objects, you can check the type of the concrete class in the SaveOperation method:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
if (myObj is Mychild1) {
Mychild1 mychild1 = (Mychild1) myObj;
// Business logic for object of type Mychild1
} else if (myObje is Mychild2) {
Mychild2 mychild2 = (Mychild2) myObj;
// Business logic for object of type Mychild2
}
}
Notice that this is not a very solid solution as, if you are creating new objects that implement your abstract class, you will have to remeber to add another branch in the if statement.
As #BojanB mentioned, the obvious solution would be to create a virtual method in your base class and override it in the derived, but if you cannot modify the code there then you can create a method for each derived class and create a dictionary that maps each type to its method:
private Dictionary<Type, Action<MyBaseAbs, MyCustomClass>> _saveOperations =
new Dictionary<Type, Action<MyBaseAbs, MyCustomClass>>();
//You can then set an entry for each of your derived classes
_saveOperations[typeof(Mychild1)] = (myObj, myCustomObj) =>
{
//Mychild1-specific logic
};
public MyCustomClass SaveOperation(MyBaseAbs obj)
{
//do the common saving operations here
var result = new MyCustomClass();
//....
var actualType = obj.GetType();
if(_saveOperations.ContainsKey(actualType))
{
_saveOperations[actualType](obj, result);
}
return result;
}
You can then add an item to the dictionary for each derived class. It is the same concept as using the is operator but allows you to add methods for more derived types without modifying the original SaveOperation method
You can use C#'s As-Operator as follows:
Mychild1 child1 = myObj as Mychild1;
if(child1 != null) {
//Here you can use child1.Mychild1Prop1 forexample
}
Link to msdn: https://msdn.microsoft.com/en-us/library/cscsdfbt.aspx

How to create fluent methods with 2 Generic Types?

I have the following classes (omitted properties for sake of simplicity):
public class Person {
public Address Address { get; set; }
public Hobby Hobby { get; set; }
}
public class Address {
public Country Country { get; set; }
}
public class Country { }
public class Hobby { }
And I created an IncludeMapper to be used, if possible, as follows:
IncludeMapper<Person> m = IncludeMapper
.For<Person>()
.Add(person => person.Address).And(address => address.Country)
.Add(person => person.Hobby);
Add will take the base type, e.g, Person.
And will take the type used in the previous Add or And.
public class IncludeMapper {
public static IncludeMapper<T> For<T>() {
return new IncludeMapper<T>();
}
}
public class IncludeMapper<T> {
public IncludeMapper<T> Add<K>(String expression, Expression<Func<T, K>> property) {
return this;
}
public IncludeMapper<K> And<K>(String expression, Expression<Func<T, K>> property) {
return this;
}
}
This won't work ... I think I need to return on the methods and I might need an extra class because the For is only for T?
Could someone help me out with this?

C#: ICollection with Interface as Type like ICollection<ILocalized>

Im working with EntitFramework which generates my Entity classes:
I have these classes:
public class Car
{
//...
public String Brand { get; set; }
//...
public virtual ICollection<CarLocalized> CarLocalizeds { get; set; }
//...
}
public class CarLocalized :ILocalized
{
public int LangID { get; set; }
public Lang Lang { get; set; }
}
public static class Helper {
public static List<String> GetLangIDList(ICollection<ILocalized> list)
{
//I want all the ID of the lang where car is translated for:
var somethin = list.Select(m => m.LCID_SpracheID.ToString()).ToList();
return somethin;
}
}
public class HomeController : Controller
{
public ActionResult Translated()
{
Car car = db.Cars.Find(2);
List<String> transletedIDs = Helper.GetLangIDList(car.CarLocalizeds);
return View(transletedIDs);
}
}
but now the Problem is that
List<String> transletedIDs = Helper.GetLangIDList(car.CarLocalizeds);
is not working. Why can i not set the signature to ICollection and give it a ICollection where CarLocalized Implements the interface which is required in the Signature??
Please help me...
THx
Problem is ICollection<T> is not "Covariant". It seems GetLangIDList method doesn't modify the list, it just queries the list. In that case you can use IEnumerable<T> which is "Covariant".
public static List<String> GetLangIDList(IEnumerable<ILocalized> list)
{
//I want all the ID of the lang where car is translated for:
var somethin = list.Select(m => m.LCID_SpracheID.ToString()).ToList();
return somethin;
}
Read more about Covariance and Contravariance in Generics and Faq

Make generic object instantiation more generic

I've got this piece of code to create new objects in a generic way:
var user = User.Create<User>(c => c.Name = "321X");
What I don't like about it is the fact I need to pass the 'generic notation' <T> for every create call. After all I create an object that I'm already referring to...
The code behind this current functionality is:
public class User : CreateBase
{
public string Name { get; set; }
}
public abstract class CreateBase
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create<T>(Action<T> init) where T : CreateBase, new()
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.DateTime = DateTime.Now;
init(obj);
return obj;
}
}
Is it possible (and how) to refactor my code to this, to create an object?
var user = User.Create(c => c.Name = "321X");
Thanks!
Define the generic argument on the class level:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public static T Create(Action<T> init)
{
//...
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
Then you can write var user = User.Create(c => c.Name = "321X");
Otherwise the compiler cannot infer the type for your Create method without specifying the type argument.
You were not very far. Try this modification:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create(Action<T> init)
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.CreateDate = DateTime.Now;
init(obj);
return obj;
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
EDIT: Updated the code after I tested it on my local environment. It works now.
You are doing it the wrong way. Instead of getting rid of the generic argument, get rid of (needlessly) saying User.. Instead:
CreateBase.Create<User>(...)
No more redundancies.
Besides that, calling a static member of the base class through a derived class is an anti-pattern.
A better approach would be to include this functionality in the constructor of the base class (I call it ModelBase)
public abstract class ModelBase
{
public DateTime CreateDate { get; private set; }
public Guid Guid { get; private set; }
public ModelBase()
{
Guid = Guid.NewGuid();
DateTime = DateTime.Now;
}
}
public User : ModelBase
{
public User()
: base()
{
}
public User(string name)
: base()
{
Name = name
}
public string Name { get; set; }
}
Creating a user the standard way will initialize the Guid and date automatically
var user = new User { Name = "xy };
EDIT
I added a second constructor with a name parameter. I you want to force the initialization of the name, drop the first parameterless constructor.
var user = new User("xy");
If you really uncomfortable with that sintax (I, honestly, don't see much problem here)
you can do the following:
public class User : CreateBase
{
public string Name { get; set; }
public static User Create(Action<User> a)
{
return Create<User>(a); //CALL BASE CLASS GENERIC FUNCTION
}
}
After you can call it in a way you would like to do that :
var user = User.Create(c => c.Name = "321X");

Categories

Resources