Convert Base class to Derived class in c#? - c#

I am trying to convert Base class to derived class object. See below code, I am having the issue when I converting. It is basic thing, but struggling.
[HttpGet]
[Route("/Edit/{Id}")]
public ActionResult Edit(int Id)
{
List<ClassA> Data = Ctx.GetClassAFromId(Id);
// Now Here I want convert ABC List<ClassA> to XyZ List<ClassA>
//How to do that?
return View(DataXYZ);
}
Model generate by EF
namespace ABC
{
public partial class ClassA
{
public string First_name { get; set; }
public string Last_Name { get; set; }
}
}
Project model
namespace XYZ
{
[MetadataType(typeof(ClassAMetadata))]
public partial class ClassA:ABC.ClassA
{
}
public class ClassAMetadata
{
[DisplayName(#"First Name")]
[Required]
public string First_name { get; set; }
[DisplayName(#"Last Name")]
[Required]
public string Last_Name { get; set; }
}
}
How Can convert ABC.ClassA to XYZ.ClassA?
Edit:
we are working on i18n project. So we need to display each text in different languages. But our EF project is in different Namespace and web project is in different Namespace. that is the reason I deriving from base class

You can't convert List<BaseClass> to List<DerivedClass>
What you can do is used linq:
listABC.Cast<XYZ.ClassA>.ToList()
But lookout - it is O(n) procedure

Even though their names are alike, they are completely different classes. It'd be just the same as if you called them Foo and Bar
You'll need a method that converts these objects. It takes a Foo object as parameter, then returns an equivalent Bar object
public Bar Foo_To_Bar(Foo myFoo)
{
return new Bar() { Prop1 = myFoo.Prop1, Prop2 = myFoo.Prop2 };
}
Something like that. You'll probably also need a method that goes the other way around if you want to convert in both directions.
Note: If the classes have properties with the same name, I suggest you look into Automapper. It automates much of the boring work for you.
Edit
Apparently, your Foo inherits from Bar. That complicates things a bit more. I'll rework this answer when I get the time.
I don't see a use case for having your ViewModel (XYZ.ClassA) derive from your base entity (ABC.ClassA). Can you explain why this is needed? I think you're misusing inheritance here.
Generally speaking, you'd want your XYZ.ClassA to have a property of type ABC.ClassA (or any IEnumerable<ABC.ClassA> variation), not inherit from it.
Can you please confirm if this is an actual requirement, or can be part of the issue and is allowed to change if it fixes your problem?

EDIT - based on the fact that one object is inherited from the other, see C#/.NET Little Wonders: Use Cast() and OfType() to Change Sequence Type
Couple of options:
1.
namespace ABC
{
public partial class ClassA
{
public ClassA(XYZ.ClassA classToConvert)
{
this.First_name = classToConvert.First_name,
this.Last_Name = classToConvert.Last_Name
}
public string First_name { get; set; }
public string Last_Name { get; set; }
}
}
Use it singularly:
var newClassA = new ABC.ClassA((XYZ.ClassA)classA)
Do it in a list:
List<ABC.ClassA> newClassAList = classAList.Select(p => new ABC.ClassA((XYZ.ClassA)p).ToList();
Or do it in a list without the above constructor and using an object initaliser
List<ABC.ClassA> newClassAList = classAList.Select(p => new ABC.ClassA{First_name = p.First_name, Last_Name = p.Last_Name}.ToList();
As others have mentioned Use AutoMapper.
Use Nuget and add AutoMapper to your project (and some initalisation code)
Create your Map:
Mapper.CreateMap<XYZ.ClassA, ABC.ClassA>();
Map your objects:
var myABCClassA= Mapper.Map<XYZ.ClassA, ABC.ClassA>(myXYZClassA);
As long as your property names on both classes match thats all the code you need

I created this today
public static void Map<T1, T2>(this T1 obj1, T2 obj2) where T1 : class where T2 : class
{
IEnumerable<(PropertyInfo p1, PropertyInfo p2)> properties = typeof(T1).GetProperties()
.Join(typeof(T2).GetProperties(), o => o.Name, t => t.Name, (o, t) => (o, t));
foreach((PropertyInfo p1, PropertyInfo p2) in properties)
{
if (p1.CanWrite && p1.PropertyType == p2.PropertyType)
{
p1.SetValue(obj1, p2.GetValue(obj2));
}
}
}

Related

Generic Extension Method with Concrete Class Override

I have a third party DLL that returns objects like Customers, Orders, etc. I'll call them Your Entities. They do have a common IYourEntity interface so I can use that as a source constraint.
I want to create a generic conversion extension method to convert all these different third party entities to My Entities with some streamlined and more maintainable code.
....but I can't figure out how to make a generic extension method that will call the concrete extension method for the specific conversion of each class.
Putting some of the main aspects of my code below, but you can get a full fiddle to play with here.
Yes, I'm probably showing I'm a bit clueless on how to do this and maybe trying to combine different concepts. Any pointers much appreciated as I've been beating my head for a couple of days now and need a life line :)
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
public static class ExtensionMethods
{
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
return new MyEntity1();
}
public static List<IMyEntity> ToMyEntityList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => q.ToMyEntity());
}
}
public class YourEntity1 : IYourEntity, IConvertToMyEntity<YourEntity1, MyEntity1>
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
public MyEntity1 ToMyEntity(YourEntity1 yourEntity)
{
return new MyEntity1()
{Id = yourEntity.Id, MyEntityName = yourEntity.YourEntityName, CreatedOn = DateTime.UtcNow};
}
public List<MyEntity1> ToMyEntityList(List<YourEntity1> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => ToMyEntity(q));
}
}
Since the classes implementing IYourEntity are from a third party and not under your control, you can't implement an own IConvertToMyEntity<T1, T2> interface upon these.
One way you can handle it is by overloads of such conversion (extension) methods.
There's no need for any generic T type arguments; the common IYourEntity interface suffices.
Suppose you have 3 classes implementing the IYourEntity interface;
e.g. YourCustomer, YourOrder and YourProduct.
These need to be converted to IMyEntity instances, of which you might have different concrete implementations;
e.g. a general MyEntity and a specific MyProduct.
For the conversion you set up an extension method targeting IYourEntity.
This extension method will be called to convert an IYourEntity to an IMyEntity in case a more specific overload of this extension method does not exist.
public static IMyEntity ToMyEntity(this IYourEntity target)
{
return new MyEntity { Id = target.Id, EntityName = "Fallback name" };
}
For the entities that require a custom conversion, you set up overloads of this extension method targeting those specific source class types.
Below are such ones for YourOrder and YourProduct (but not for YourCustomer).
public static IMyEntity ToMyEntity(this YourOrder target)
{
return new MyEntity { Id = target.Id, EntityName = target.OrderName.ToUpper() };
}
public static IMyEntity ToMyEntity(this YourProduct target)
{
return new MyProduct { Id = target.Id * 100, EntityName = target.ProductName };
}
Next, define the extension method to convert the list of IYourEntity instances to a list of IMyEntity instances. In the code below, the inbetween cast to dynamic enables that the appropriate ToMyEntity overload will be called.
Note that the ToMyEntity methods don't have to be extension methods, but it might be convenient to have these in place in case you need to convert a single instance instead of a list.
public static List<IMyEntity> ToMyEntities(this List<IYourEntity> target)
{
var myEntities = new List<IMyEntity>();
foreach (var yourEntity in target)
{
var myEntity = Extensions.ToMyEntity((dynamic)yourEntity);
myEntities.Add(myEntity);
}
return myEntities;
}
An example - .net fiddle
var yourEntities = new List<IYourEntity>()
{
new YourCustomer() { Id = 1 },
new YourOrder() { Id = 2, OrderName = "Order-2"},
new YourProduct() { Id = 3, ProductName = "Product-3"}
};
var myEnties = yourEntities.ToMyEntities();
myEnties.ForEach(o => Console.WriteLine("{0} - {1} ({2})",
o.Id, o.EntityName, o.GetType().Name
));
The output of the example above looks like below.
Notice how the YourCustomer instance was handled by the general IYourEntity conversion, whereas the YourOrder and YourProduct instances got a specific treatment.
1 - Fallback name (MyEntity)
2 - ORDER-2 (MyEntity)
300 - Product-3 (MyProduct)
You can change your extension method to this:
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
if (yourEntity is IConvertToMyEntity<IYourEntity, IMyEntity> convertible)
return convertible.ToMyEntity;
return new MyEntity1();
}
This will not work in most cases unless you also make your interface co- and contra-variant:
public interface IConvertToMyEntity<in TYourEntity, out TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
It is still not completely clear to me how you can make a third party class implements IConvertToMyEntity that easily. Assuming you did this only to show us your actual goal, you should be very careful with what you are trying to accomplish in the Main.
If you use a List<IYourEntity>, you can only use methods and properties defined in the interface, unless you know what you are doing with specific cast. The need for List<IYourEntity> or List<IMyEntity> limits a lot the implementation of a custom mapper between My classes and Your classes. Here a possible solution:
As I said, I did not change Your classes:
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public class YourEntity1 : IYourEntity
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
}
Also My classes are very simple and do not contain any logic for the mapping. This is a debatable choice, but I generally prefer to keep conversion logic separated from the classes involved. This helps to maintain clean your code in case you have several conversion functions for the same pair of classes. By the way, here they are:
public interface IMyEntity
{
int Id
{
get;
set;
}
DateTime CreatedOn
{
get;
set;
}
}
public class MyEntity1 : IMyEntity
{
public int Id
{
get;
set;
}
public string MyEntityName
{
get;
set;
}
public DateTime CreatedOn
{
get;
set;
}
}
And this is how I designed the custom converter
public interface IMyEntityConverter
{
IMyEntity Convert(IYourEntity yourEntity);
}
public class MyEntity1Converter : IMyEntityConverter
{
public IMyEntity Convert(IYourEntity yourEntity)
{
var castedYourEntity = yourEntity as YourEntity1;
return new MyEntity1()
{
Id = castedYourEntity.Id,
MyEntityName = castedYourEntity.YourEntityName,
CreatedOn = DateTime.UtcNow
};
}
}
It is clear the lack of genericity, but you cannot do otherwise if you need an extension method on a List of generic My and Your classes. Also tried with covariant and contravariant interfaces but C# does not let you use them with this implementation.
Now the core of the solution: you need something that binds Your class to the My class with a custom converter, and all of this should be as more transparent as possible.
public class EntityAdapter<YourType, MyType>
where YourType : IYourEntity
where MyType : IMyEntity
{
protected YourType wrappedEntity;
protected IMyEntityConverter converter;
public EntityAdapter(YourType wrappedEntity, IMyEntityConverter converter)
{
this.wrappedEntity = wrappedEntity;
this.converter = converter;
}
public static implicit operator YourType(EntityAdapter<YourType, MyType> entityAdapter) => entityAdapter.wrappedEntity;
public static explicit operator MyType(EntityAdapter<YourType, MyType> entityAdapter) =>
(MyType) entityAdapter.converter.Convert(entityAdapter.wrappedEntity);
public MyType CastToMyEntityType()
{
return (MyType) this;
}
}
The pseudo-transparency here is given by the implicit cast to Your class. The advantage is that you can cast this EntityAdapter to an instance of a My class by calling CastToMyEntityType or the explicit operator overload.
The painful part is with the extension methods:
public static class EntityAdapterExtensions
{
public static List<IMyEntity> ToIMyEntityList(this List<EntityAdapter<IYourEntity, IMyEntity>> lstEntityAdapters)
{
return lstEntityAdapters.ConvertAll(e => e.CastToMyEntityType());
}
public static List<EntityAdapter<IYourEntity, IMyEntity>> ToEntityAdapterList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.Select(e =>
{
switch (e)
{
case YourEntity1 yourEntity1:
return new EntityAdapter<IYourEntity, IMyEntity>(yourEntity1, new MyEntity1Converter());
default:
throw new NotSupportedException("You forgot to map " + e.GetType());
}
}).ToList();
}
}
The first one is pretty straightforward to understand, but the second one is definitely something that require maintenance. I gave up on generics for the reasons already explained, so the only thing left to do is to create the EntityAdapters starting from the actual entity types.
Here is the fiddle
This may be a little controversial but maybe a different way is better?
Firstly, and this is more for my sake, I would suggest more easily understandable terminology so instead of 'your' and 'my' I would use 'source' and 'dest'.
Secondly I wonder if the generics route is necessary? I'm assuming (and I may be wrong) that for each of the classes you have coming from your third-party assembly, you have a specific class for it to be converted to. So maybe this could be achieved much more easily with a constructor override in your destination class.
// third party class example
public class SourceClass
{
public int Id { get; set; }
public string Name { get; set; }
}
// the destination class in your project
public class DestClass
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
// default constructor
public DestClass()
{
}
// conversion constructor
public DestClass(SourceClass source)
{
Id = source.Id;
Name = source.Name;
CreatedOn = DateTime.UtcNow;
}
}
This way you convert a single instance using:
// source being an instance of the third-party class
DestClass myInstance = new DestClass(source);
And you can convert a list with LINQ:
// source list is IList<SourceClass>
IList<DestClass> myList = sourceList.Select(s => new DestClass(s)).ToList();
If you wanted to you could implement extensions for your conversions. This again would not be generic as you'll need one for each class pairing but as it's an alternative to writing a converter class for each, it will be overall less code.
public static class SourceClassExtensions
{
public static DestClass ToDest(this SourceClass source)
=> new DestClass(source);
public static IList<DestClass> ToDest(this IList<SourceClass> source)
=> source.Select(s => new DestClass(s)).ToList();
}
If you still want something generic then you'll want a converter for each class pair, implementing a suitable interface. Then I'd recommend a converter factory class where you'll need to register the specific converters either into a dictionary in the class or via dependency injection. I can go into this further if you'd prefer but I think it would be more complicated.
sorry for writing here its not an actual answer,
there is no option for generically to do this
you have to write for every entity
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
I saw this code from your question.
It depends on what you want to do after transformation
you should use data mapper
public class MapProfile : Profile
{
public MapProfile()
{
CreateMap<TYourEntity , TMyEntity >();
CreateMap<TMyEntity , TYourEntity >();
}
}

Yet another question how to reduce code duplication in C#

I have two objects, lets call them A and B.
Each contain the following property:
[IgnoreDataMember]
public string SalesforceId { get; set; }
Then I have another two objects, lets call them UpdatedA and UpdatedB, which respectively extend A and B, and include nothing but:
[DataMember(Name = "sf__Id")]
public new string SalesforceId { get; set; }
[DataMember(Name = "sf__Created")]
public bool SalesforceCreated { get; set; }
The reason for this is so that I can use ServiceStack to convert A and B to CSV files and then use it again to convert CSV files from Salesforce back to C# Objects (If I don't ignore SalesforceId, the upload to Salesforce Bulk API 2.0 will fail).
So, the first question part of this question is do I really need to create two separate classes for UpdatedA and UpdatedB, as these classes are nearly identical and are actually both poltergeists, because I only use them in the following two methods:
private Dictionary<string, A> Update(Dictionary<string, A> aByExternalIds, RelayerContext context) {
IConfiguration config = context.Config;
string url = $"{config["SalesforceInstanceBaseUrl"]}/services/data/{config["SalesforceVersion"]}/jobs/ingest/{context.job.Id}/successfulResults";
this.restClient.Get(url, context.token)
.FromCsv<List<UploadedA>>()
.ForEach((updatedA) => {
if (aByExternalIds.TryGetValue(updatedA.ExternalId, out A oldA)) {
oldA.SalesforceId = updatedA.SalesforceId;
}
});
return aByExternalIds;
}
private Dictionary<string, B> Update(Dictionary<string, B> bBySalesforceAId, RelayerContext context) {
IConfiguration config = context.Config;
string url = $"{config["SalesforceInstanceBaseUrl"]}/services/data/{config["SalesforceVersion"]}/jobs/ingest/{context.job.Id}/successfulResults";
this.restClient.Get(url, context.token)
.FromCsv<List<UploadedB>>()
.ForEach((updatedB) => {
if (bBySalesforceAId.TryGetValue(updatedB.A__c, out B oldB)) {
oldB.SalesforceId = updatedB.SalesforceId;
}
});
return bBySalesforceAId;
}
Which leads to the second part of this question.
Both of these questions are very similar. We can see that the inputs are mapped by different properties on A and B... so I think I could do something like create an interface:
public interface Identifiable {
public string getIdentifier();
}
which would could be used to return either updatedA.ExternalId or updatedB.A__c.
But I'm not sure what the method signature would look like if I'm using generics.
Also, if I don't know how I could handle FromCsv<List<UploadedA>>() and FromCsv<List<UploadedB>>() in a generic way (maybe passing in a function?)
Anyway, to sum up, what I'd like to do is reduce those these two methods to just one, and if I can remove one or both of those Uploaded classes, so much the better.
Any ideas?
How about something like this:
public interface IBase
{
string SalesforceId { get; set; }
}
public class A : IBase
{
public string SalesforceId { get; set; }
}
public class UploadedA : A
{
public new string SalesforceId {
get => base.SalesforceId;
set => base.SalesforceId = value; }
public bool SalesforceCreated { get; set; }
}
public static void Update<T, TU>(Dictionary<string, T> oldBySalesForceId, Func<TU, string> updatedId)
where TU : T
where T : IBase
{
// Call service and read csv to produce a list of uploaded objects...
// Substituting with an empty list in the example
var list = new List<TU>();
foreach (var updated in list)
{
if (oldBySalesForceId.TryGetValue(updatedId(updated), out var old))
{
old.SalesforceId = updated.SalesforceId;
}
}
}
I have removed some details that did not seem relevant for the example. This uses generics with constraints and a interface to ensure both the updated and old value has a SalesForceId.
I changed the derived class so that it uses the same SalesforceId as the base class, you could change it to virtual/override if you prefer, but it is probably not a good idea that the base and derived class both have independent properties with the same name since it will be confusing.
It uses a delegate to describe the id/key for UpdatedA/UpdatedB. You could use an interface instead if you prefer.

Convert instance method to class method C#

I have a instance method that creates a new instance of a class. I would like for this to be a class method. The problem is that I get an error when trying to call GetType() in the static method. Is it possible to convert this method to a static method ?
error
An object reference is required for the non-static field, method or property 'object.GetType()'.
Customer.New
public object WithAttributes(ExpandoObject valueObject)
{
var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetSetMethod() != null);
var self = Activator.CreateInstance(GetType());
var values = (IDictionary<string, object>)valueObject;
foreach (var property in properties)
{
if (values.Keys.Contains(property.Name))
{
var val = values[property.Name];
property.SetValue(self, values[property.Name]);
}
}
return self;
}
BaseEntity.cs
public class BaseEntity
{
public Int64 Id { get; set; }
public DateTime AddedDate { get; set; }
public DateTime ModifiedDate { get; set; }
public string IPAddress { get; set; }
public object WithAttributes(ExpandoObject valueObject)
{
// Same code as above
}
}
Customer.cs
public class Customer : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string MobileNo { get; set; }
}
Desired Usage
dynamic attributes = new ExpandoObject();
attributes.FirstName = "James";
attributes.LastName = "Jones";
var customer = Customer.WithAttributes(attributes);
Well, Unfortunately for you it is impossible to get the implementing type from the base abstract type's static method. According to reed copsey's answer here and to Jon Skeet's answer there. As you can see in Jon's answer, the c# compiler associate the static method to the type it was declared in, even if it was executed from a deriving type.
This means that your abstract class must be aware of the type that implements it, or at least this method must be aware of the type where it's called from.
One way to do it is to create the WithAttributes as a generic method:
public static T WithAttributes<T>((ExpandoObject valueObject)) where T: BaseEntity, new
{
// Here you can use typeOf(T)
}
This have some advantages (for instance, you can simply write var self = new T() instead of using Activator.CreateInstance(), and you don't need to return an object but the actual type.
However, you can't force the code that's calling this method to pass the correct type - nothing is stopping you from doing something like this:
var customer = Customer.WithAttributes<SomeOtherBaseEntityDerivedClass>(attributes);
Rob Leclerc's answer here Is another attempt to solve this using generics, Only this is creating the entire abstract class as a generic class, so instead of public class BaseEntity you will have
public class BaseEntity<TChild>
and then you can use typeOf(TChild).
This has the same disadvantage as my suggestion (you can do public class Customer : BaseEntity<SomeOtherType> just as easily).
Daniel A. White Answered his own question by taking the type as a parameter to the static method in the abstract class:
public static object WithAttributes(Type type, ExpandoObject valueObject)
Again, it has the same drawbacks as using the generic approach, but it also have the drawbacks of your approach - it must return object and you must use Activator.CreateInstance.
To conclude - What you are asking for can't be done safely.
I will not recommend using any of these approaches for a public API, but If you know your team are the only programmers that will inherit the BaseEntity, I would probably go with the generic approach, as long as you make sure everybody knows the compiler can't protect them from using the wrong type parameter.

return a class containing generic List

I'm trying to construct a class in c# (5.0) that I can use as a base class and it contains a List, but List could be 2 different types. I want to do the following:
public class BaseC
{
string header { get; set; }
List<object> recs { get; set; }
}
public class derive1: BaseC
{
List<myclassA> recs;
}
public class derive2: BaseC
{
List<myclassB> recs;
}
and importantly what I want to do is return the derived classes from a method in another class:
public BaseC PopulateMyDerivedClass()
{
BaseC b = new BaseC();
b.header = "stuff";
b.recs = FileHelperEngine<myclassB> fhe.ReadStringAsList(x);
}
the main point is that method PopulateMyDerivedClass really does the exact same thing for both derive1 and derive2, just that it returns a different type of list.
I think I need generics. But is that at the base class level and also is PopulateMyDerivedClass then supposed to return a generic? I think that perhaps I am not dealing with polymorhpism, but as you can guess I am new to generics, so struggling.
I think what you want is to make BaseC a generic class and specify the generic when defining the derived classes:
public class BaseC<T>
{
//...
virtual List<T> Recs { get; set; }
}
public class Derived1 : Base<MyClassA>
{
override List<MyClassA> Recs { get; set; }
}
Good point by Alexei Levenkov:
Usual note: DerivedX classes in this case will not have common parent unlike original sample. One may need to add more layer of classes (as non-generic parent of BaseC) or use an interface if DerivedX need to be treated as having common parent/interface.
I get the feeling that your code design could use some rethinking. For one, typically when we talk about "polymorphism", we are usually talking about polymorphic behaviors (methods), rather than members. I think you might want to consider two classes that implement an interface that does all the things you want each class to do (parses data into its own type of list and acts on it as you need it to).
Nevertheless, without getting way into the details of your code, I think something like this might be what you were trying to achieve:
public class BaseC<T>
{
string header { get; set; }
public List<T> recs {get;set;}
}
and
public BaseC<T> PopulateClass<T>()
{
var b = new BaseC<T>();
b.recs = new List<T>();
T first = (T)Convert.ChangeType("1", typeof(T));
b.recs.Add(first);
return b;
}
And to check our sanity:
BaseC<String> d1 = PopulateClass<String>();
System.Diagnostics.Debug.Print(d1.recs.First().ToString());
System.Diagnostics.Debug.Print(d1.recs.First().GetType().ToString());
BaseC<int> d2 = PopulateClass<int>();
System.Diagnostics.Debug.Print(d2.recs.First().ToString());
System.Diagnostics.Debug.Print(d2.recs.First().GetType().ToString());
prints
1
System.String
1
System.Int32

How do i extend a property through inheritance?

i have a class Product that contains a Dictionary with a price curve. The key is a string that can be parsed to a TimeStamp.
public class Product
{
public virtual int Id { get; set; }
public virtual IDictionary<string, decimal> PriceList { get; set; }
public Product()
{
this.PriceList = new Dictionary<string, decimal>();
}
}
Now i need a second class with more prices for each key
public class SpecialProduct : Product
{
public enum PriceType
{
BusineesDays,
Weekends,
Holidays
}
public virtual IDictionary<string, IDictionary<PriceType, decimal>> PriceList { get; set; }
public SpecialProduct()
{
this.PriceList = new Dictionary<string, IDictionary<PriceType, decimal>>();
}
}
I am not sure if this is a good approach for this case. I would also like to constrain the enum type to decimal. Any ideas?
UPDATE: I forgot to mention that i need to save all products i a generic List (List)
This is hiding a member.
Polymorphism means changing method, property implementation in some subclass, say it "derived" or "inherited" class. But, anyway, it's signature is immutable.
C# provides a good way of hiding members: the "new" keyword.
You just need to put "new" before access modifier in the derived class and you got it. If you don't do that, C# compiler will suggest you to do that.
By the way, if your goal is using polymorphism, you should take generics in account.
Your base class should have a "TPriceValue" generic parameter and it'll look like this:
public class Product<TPriceValue>
{
public virtual int Id { get; set; }
public virtual TPriceValue PriceList { get; set; }
public Product()
{
// NOTE/EDIT: You wouldn't initialize "PriceList" here...
}
}
So, if you want your price value to be a decimal, you should instantiate your class this way:
new Product<decimal>();
Or, if you want that your value as another dictionary:
new Product<IDictionary<PriceType, decimal>>();
If I'm not wrong, this is the way to go in your case ;)
EDIT: Sorry I forgot to change something in your base class, check again this answer :)
I would go for simplification, since this code has a certain bad smell to it.
Why don't you use the PriceList in SpecialProduct inside Product as well, and make the sub-dictionary have just one value always of PriceType.Default or something like that? You would then be able to use all Products without requiring any casts or checks.
What about this approach?
public abstract class AProductBase<T>
{
public IDictionary<string, T> PriceList { get; set; }
...
}
public class Product : AProductBase<decimal>
{
...
}
public enum PriceTypeEnum { ... }
public class SpecialProduct : AProductBase<IDictionary<PriceTypeEnum, decimal>>
{
...
}
Perhaps this fits better your requirements.
Regards

Categories

Resources