Automapper automatically resolve correct subclass to map to? - c#

Given the following source types:
public class BaseViewModel
{
public string Prop1 { get; set; }
}
public class FirstViewModelImpl : BaseViewModel
{
public string Prop2 { get; set; }
}
public class SecondViewModelImpl : BaseViewModel
{
public string AnotherProp { get; set; }
}
And the following destination types
public class BaseDto
{
public string Prop1 { get; set; }
}
public class FirstDtoImpl : BaseDto
{
public string Prop2 { get; set; }
}
public class SecondDtoImpl : BaseViewModel
{
public string AnotherProp { get; set; }
}
With the following mappings:
Mapper.CreateMap<FirstViewModelImpl,FirstDtoImpl>();
Mapper.CreateMap<SecondViewModelImpl,SecondDtoImpl>();
Can I do the following (trivial example) - given that I don't actually know the type of viewmodel until runtime?
BaseViewModel myViewModel = GetAViewModelFromSomewhere();
FirstDtoImpl dto = (FirstDtoImpl)Mapper.Map<BaseViewModel,BaseDto>(myViewModel);
I am trying this out now anyway!

I have found that if I change the mappings to
Mapper.CreateMap<BaseViewModel,BaseDto>()
.Include<FirstViewModelImpl,FirstDtoImpl>()
.Include<SecondViewModelImpl,SecondDtoImpl>();
Mapper.CreateMap<FirstViewModelImpl,FirstDtoImpl>();
Mapper.CreateMap<SecondViewModelImpl,SecondDtoImpl>();
Then it works as expected without using the type converter.

You can't do that directly, however you can work around it with a TypeConverter.
In the Mappings you will add:
Mapper.CreateMap<BaseViewModel, BaseDto>()
.ConvertUsing<MyTypeConverter>();
Then you can create the converter like so:
public class MyTypeConverter : TypeConverter<BaseViewModel, BaseDto>
{
protected override BaseDto ConvertCore(BaseViewModel tViewModel)
{
BaseDto vResult = null;
if(tViewModel is FirstViewModelImpl)
{
var vSource = tViewModel as FirstViewModelImpl;
vResult = Mapper.Map<FirstViewModelImpl,FirstDtoImpl>(vSource);
}
else if(tViewModel is SecondViewModelImpl )
{
var vSource = tViewModel as SecondViewModelImpl ;
vResult = Mapper.Map<SecondViewModelImpl ,SecondDtoImpl>(vSource);
}
return vResult;
}
}
Then you can use it like:
BaseDto dto= Mapper.Map<BaseViewModel,BaseDto>(myViewModel);
and have dto actually be of the type you wanted.
It won't map the Base types to each other though. If that matters I can twist it a bit more.

Can you use an interface instead? Also, there is a non-generic Mapper.Map implimentation that might work better in this case. If you have the mapping set up, you can just pass in the type.

No this is not correct if you create Mapping for derived types you should when
map objects specify the derived class also

Related

How to get members of abstract class using reflection?

I have following:
var type = typeof(ExampleClass);
public abstract class ExampleClass
{
public string Name { get; set; }
public abstract class InternalExampleClass
{
public string InternalName { get; set; }
}
}
How can I get the value of Name, InternalName?
I tried to use type.GetFields() but it doesn't return InternalName
help me, please
I can't answer all points of your question. But I can give you an idea how to start.
You don't have access to constants, but there is a workaround. First, you need an instance of your abstract class in order to use reflection. Since you can't create an object of an abstract class, you need a class which inherits it. This class contains properties set to the value of your constants.
public class InheritedReportAPI : ReportAPI
{
public string constName { get; } = ReportAPI.Name;
public string constSignatureBase { get; } = ReportAPI.SignatureBase;
public string constEventsReportsDeleted { get; } = ReportAPI.Events.ReportsDeleted;
}
Then you can use Reflection to get names and/or values of these properties.
var inheritedReportApi = new InheritedReportAPI();
var propertyList = inheritedReportApi.GetType().GetProperties();
foreach(var property in propertyList)
System.Console.WriteLine($"{property.Name}: {property.GetValue(inheritedReportApi)}");
The result:
constName: reports
constSignatureBase: /report/reports
constEventsReportsDeleted: reports_deleted

Add en extra property to a random class in generic way

Imagine I have this class
public MyClass
{
public string FullName { get; set; }
}
I have an api client that returns me this object like this with an extra property called Capitalized which capitalized all string properties for exemple.
public MyResult : MyClass
{
public MyClass Capitalized { get; set; }
}
Then I can access things like this :
MyResult result = /* call to api with my class */
Console.WriteLine(result.FullName);
Console.WriteLine(result.Capitalized.FullName);
Is there a way to define a generic MyResult like this, because T can be MyClass, YourClass and the response will always be like :
public MyResult<T> : T
{
public T Capitalized { get; set; }
}
EDIT : thanks to #Maruf reply
Eric Lippert explains it here why it is impossible : https://stackoverflow.com/a/5890813/1026105
How about that:
public class MyResult<T> : MyClass where T : MyClass
{
public T Capitalized { get; set; }
}

Initiate List<ChildClass> into List<ParentClass>

I have troubles with finding the correct words for this question, so I will try to show you with some code what my problem is.
I have a parent class, which looks like this:
public class ParentClass {
public Guid ParentId { get; }
public int ParentProperty { get; set; }
public List<ParentClass> ParentList { get; set; }
public ParentClass() {
this.ParentId = Guid.NewGuid();
}
}
It is rather simple: It got an ID, a few properties and a List containing elements of itself.
Now I am creating a child class, which looks like this:
public class ChildClass : ParentClass {
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ChildClass>();
}
}
This one got one extra property and a constructor, which contains the problem. I can't initiate a List into the declaration of the List.
I can't just do the declaration of the list in the child class, as I need it in the parent class when I am using it.
What is the best way to solve this problem?
You should use an interface that point both classes (ParentClass as well as ChildClass).
A generic type having a certain type-parameter is a "new" type: So List<ChildClass> and List<ParentClass> are different types.
I think the easiest way to achieve what you want is to initiate the list with its base type : List<ParentClass>
public class ChildClass : ParentClass
{
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ParentClass>();
}
public void AddSomething()
{
// this is ok :
this.ParentList.Add(new ChildClass());
}
}
This could work only if the type List<T> were covariant in T, also known as "out T". However, it is not, and cannot be.
The type List<> allows Add, Insert and others, and so it is not semantically covariant.
In C# (as of currently), class types cannot be made covariant. That is not supported. Only interface and delegate types can be made covariant (or contravariant) in their generic parameters.
The closest we get is IReadOnlyList<out T> which is covariant, so:
IReadOnlyList<ParentClass> parentList = new List<ChildClass>();
is allowed. However, it is not helpful in your case.
public class ParentClass<TChild> where TChild : class
{
public List<TChild> ParentList { get; set; }
public Guid ParentId { get; set; }
public int ParentProperty { get; set; }
public ParentClass()
{
ParentId = Guid.NewGuid();
ParentList = new List<TChild>();
}
}
public class ChildClass : ParentClass<ChildClass>
{
public string ChildProperty { get; set; }
}

How to create and set a polymorphic property?

I want to create a class that can take different types of value in a property. I am trying to do this using polymorphism, but I am not still learning how to do this properly, hence my request for advice.
I have a base class and two classes that inherit from it:
public abstract class BaseClass
{
public string Name { get; set; }
public Unit Unit { get; set; }
}
public class DerivedClassFloat : BaseClass
{
public float Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass
{
public string Value { get; set; }
public override string ToString()
{
return Value;
}
}
All is good, I can create a List and add different specialized subclasses. My problem comes when I need change the values of the items in my list:
foreach (var item in ListOfBaseClasses)
{
if(item is DerivedClassFloat)
((DerivedClassFloat) item).Value = float.NaN;
if (item is DerivedClassString)
((DerivedClassString) item).Value = string.Empty;
}
According to what I have read, that looks like a code smell. Is there a better way to access the value property of my derived classes based on the type I am trying to assign?
What about when you want to create the right subclass based on the value?
BaseClass newClass = null;
if (phenotype is DerivedClassFloat)
newClass = new DerivedClassFloat(){Value = 12.2};
if (phenotype is DerivedClassString)
newClass = new DerivedClassString(){Value = "Hello"};
I read about overriding virtual methods, but that works if I want to process the value, not to add or change it … maybe I am missing something?
I should make this more concrete, my apologies, I am not used to post question in this great site.
I need a property that is made of a list of attributes. Each attribute has a name and a value, but the value can be of different types. For example:
public class Organism
{
public string Name { get; set; }
public List<Attribute> Attributes { get; set; }
}
public class Attribute
{
public string AttributeName { get; set; }
public object AttributeValue { get; set; }
}
For a given organism I can have several attributes holding different value types. I wanted to avoid using the object type so that I don’t have to cast to the right type. I though property polymorphism was the solution to handle this case elegantly, but then I found myself using If ..Then which didn’t seem too different from casting in the first place.
If in your particular case you want to reset Value, you can define an abstract ResetValue method in the base class, which will be implemented by the derives classes.
As for your second case, you should check out Creational Design Patterns, and specifically the Factory and Prototype design patterns.
You can use generics to define the type and the implementing subclass will set the Value type to the type constraint:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedFloat : BaseClass<float> {}
public class DerivedString : BaseClass<string> {}
You can use Generics for this particular case:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
}
public class DerivedClassFloat : BaseClass<float>
{
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass<string>
{
public override string ToString()
{
return Value;
}
}
Polymorphic behaviour works on abstraction. Based on what your trying to do, you can reduce code smell to moving as much of your variability in code to base classess.
i would suggest is instead of property write method like as follows. You can something like as follows.
public void setValue(string val, Type type);//move this to your base class
Class MyValue{
private string strVal;
private int intVal;
//constructor
MyValue(string val, Type type){
//check the type enum here and set the values accordingly
}
}
then when set values
foreach (var item in ListOfBaseClasses)
{
item.setValue = MyValue("",Type.INT);
}
I'm not quite sure what you are trying to achieve with this approach - the Value properties are not of the same type, there is also no Value property on the base class which suggests that other types derived from the base class might not have it at all.
If all of your classes require a Value property, then maybe it should be of the most general type object - you could put it onto the base class, but that would require casting the values in the derived classes.
But then you could have a NullObject to represent an absence of value that you could assign to the Value property for every derived class.
You can use the abstract factory pattern. Consider this example:
// Base class
class Button
{
protected Button()
{
}
public string Name { get; set; }
}
// Factory interface
public interface ButtonFactory
{
Button CreateButton();
}
// And the concrete classes
class WindowsButton : Button
{
// ...
}
class WindowsButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new WindowsButton();
}
}
class MacButton : Button
{
// ...
}
class MacButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new MacButton();
}
}
Furthermore, you can combine the abstract factory pattern with the strategy pattern to encapsulate the custom behaviors that change with type.

In C# is there no way to make a class define a field using an Interface or abstract class?

I would like to force a set of classes to define three fields (of type string).
In an abstract class, I get that fields cannot be abstract and in an interface, I get an error saying that an interface cannot contain a field.
Is there no way to do this or am I not understanding this correctly? I'd rather not use methods because for some weird reason, the parentheses annoy me.
You can use properties for that:
interface MyInterface {
string Prop1 { get; set; }
string Prop2 { get; set; }
string Prop3 { get; set; }
}
Interface or abstract members force derived classes to provide code.
Fields don't have code.
You should use a property, which can be used like a field, but has code.
You can use Properties instead of fields:
// works similarly for Interfaces too
abstract class MyAbstractClass { public virtual string MyProperty1 { get; set; } }
class MyConcreteClass : MyAbstractClass { }
Then you can access MyProperty1 from any instance derived from MyAbstractClass:
MyAbstractClass obj1 = new MyConcreteClass;
obj1.MyProperty1 = "abcd";
Like everyone else says, use properties instead of fields, but you can do something like I interpreted in the comments as follows for read-only members:
abstract public class Base
{
abstract public string Foo { get; }
abstract public string Bar { get; }
abstract public string Baz { get; }
}
public class Derived : Base
{
public override string Foo { get { return "foo"; } }
public override string Bar { get { return "bar"; } }
public override string Baz { get { return "baz"; } }
}
If you want the fields to be modifiable later, you'll have to either use automatic properties or declare concrete backing fields and getter/setter pairs for each property.

Categories

Resources