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; }
}
Related
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
I have a situation where I need to get the value on a property on an attribute (decorator) applied to a class. That class that is decorated, is inheriting from an abstract class. It is this abstract class that needs to get the attribute information, but it needs to do so inside a static function.
I cannot post the exact scenario, but here is a terrible example that could do without attributes, but please work with it as it is:
public class VehicleShapeAttribute : Attribute
{
public string Shape { get; }
public VehicleShapeAttribute(string shape)
{
Shape = shape;
}
}
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public static string GetVehicleShape()
{
//return value from the attribute, from this static function. CANT DO THIS HERE
return AnyInheritingClass.VehicleShapeAttribute.Shape;
}
}
[VehicleShape("sedan")]
public class VauxhaulAstraSedan : Vehicle
{
//calling GetVehicleShape() on this class should automatically return "sedan"
}
Is this possible?
This is a bad example but I cannot post the actual code
Make the method non-static and resolve the runtime type with this.GetType():
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public string GetVehicleShape()
{
var attribute = Attribute.GetCustomAttribute(this.GetType(), typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
}
For a static version, you'll need to accept a Vehicle parameter whose type you can then inspect:
public static string GetVehicleShape(Vehicle vehicle)
{
var attribute = Attribute.GetCustomAttribute(vehicle.GetType());
// ...
Alternatively (and I'm just copy/pasting Mathias' code into another form syntactically here) if you really need to have the method static because you don't want to create an instance, you can add the following method to your attribute code (or any other static class, but I like to put it there with the attribute):
public static string GetFrom<T>()
{
return GetFrom(typeof(T));
}
public static string GetFrom(Type t)
{
var attribute = Attribute.GetCustomAttribute(t, typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
Then you could write code like:
var shape = VehicleShapeAttribute.GetFrom<VauxhaulAstraSedan>();
or
var shape = VehicleShapeAttribute.GetFrom(typeof(VauxhaulAstraSedan));
or even
var vehicle = new VauxhaulAstraSedan();
var shape = VehicleShapeAttribute.GetFrom(vehicle.GetType());
I have the following classes:
//some base class
public abstract class MyObject<T>{
public static T FromObject(object anotherObject){
var t = Activator.CreateInstance<T>();
// some reflection logic here
return t;
}
}
public class Product: MyObject<Product>{
}
public class ProductCart: MyObject<ProductCart>{
public ICollection<Product> Products{get;set;}
}
public class Basket: ProductCart{
public int BasketId{get;set;}
}
public class Order: ProductCart{
public int OrderId{get;set;}
}
So now I could build my model like this:
var products = serviceContext.Products.Select(Product.FromObject).ToList(); // no problem here
var basket = Basket.FromObject(serviceContext.Basket); // problem is here - instance of ProductCart is returned
var order = Order.FromObject(serviceContext.Order); // same problem, instance of ProductCart
Is there a way somehow to solve it and get converted Basket and Order instead of base ProductCart?
The goal is:
var basket = Basket.FromObject(serviceContext.Basket); // return instance of Basket inherited from ProductCart
Thanks for helping.
If you can change the class definitions, you can pass along the type to ProductCart, like so:
public class ProductCart<T> : MyObject<T> { }
public class Basket : ProductCart<Basket> { }
public class Order : ProductCart<Order> {}
In your definition you tell Basket.FromObject to explicitly return ProductCarts (by inheriting from MyObject<ProductCart>).
And if you're unable to change the inherit tree, you can choose to hide the original method (or place it in a factory):
public class Basket : ProductCart
{
public int BasketId { get; set; }
public Basket FromObject(object anotherObject)
{
return MyObject<Basket>.FromObject(anotherObject);
}
}
That's because Basket is a MyObject<ProductCart>, and not a MyObject<Basket>.
If you don't want to redefine your hierarchy, you should define the return type of the static method according to the object you pass, like in this example:
using System;
public abstract class MyObject<T> {
public static TOtherObject FromObject<TOtherObject>(TOtherObject anotherObject) where TOtherObject : MyObject<T> {
var newOtherTypeInstance = Activator.CreateInstance<TOtherObject>();
// some reflection logic here
return newOtherTypeInstance;
}
}
public class ProductCart : MyObject<ProductCart> {
}
public class Basket : ProductCart {
public int BasketId { get; set; }
}
public class Order : ProductCart {
public int OrderId { get; set; }
}
class Program {
static void Main(string[] args) {
Order o = new Order();
var basket = Basket.FromObject(o);
}
}
Of course, at this point the actual implementation of the comment "some reflection logic here" could get much more complicated :)
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; }
}
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