Reputation: 505
This is my situation: I have classes represeting properties:
public abstract class RootProperty {
public int Id {get; set;}
}
public class AProperty {}
public class BProperty {}
and let there be a looot of these:
public class ZProperty {}
And a value for each of this properties,
public abstract class RootValue {
public RootProperty Property {get;set;}
}
public class AValue : RootValue {
public AValue(AProperty) { ... }
public string Value {get; set;}
}
public class ZValue : RootValue {
public ZValue(ZProperty) { ... }
public sometipe Value {get;set;} }
In fact, each class is representing a type of property than a thing must have. So if i want to say that a property is defined by a string wich must have value in a given domain i say:
public class DomainProperty {
public ICollection<string> Domain {get; set;}
}
public class DomainValue {
public DomainValue(DomainProperty) {...}
public string Value
{
set {
if (!this.Property.Domain.Any(d=>d==value)) {
throw new Exceptin("Value out of range!");
}
}
}
}
So I can dogs can be small or big, and mine is big.
DomainProperty DogsSize = new DomainProperty { Domain= ["big","small"] }
DomainValue MyDogSize = new DomainValue(color) { Value = "big" }
Using this, I can define properties on numeric ranges with max and min value, etc. Okey, the first question here is: can you think some other solution for this problem of coustomizable types of properties?
Now, the questio that bring me to post here: The previous logic is on the server side, and its reciving from the client side a list of abstract dtos:
public abstract class RootDto { public int PropertyId { get; set; } }
public class ADto : RootDto { public string Value { get; set; } }
public class BDto: RootDto { public bool Value { get; set; } }
public class ZDto : RootDto { public someothertype Value { get; set; } }
With RootDto PropertyId I can find the original RootProperty. I want to create a new instance of ?Value, and set the value to ?Dto.Value. Now I have this on a lot of casts:
List<RootDto> listDto;
foreach(dto in listDtio) {
if (someDto is ADto) {
ADto castedDto = (ADto) dto;
AProperty dtoProperty = (AProperty) Repository.findRootProperty(dto.PropertyId);
AValue valueForDto = new AValue(dtoProperty);
valueForDto.Value = castedDto.Value;
}
if ...(B.....Z)
}
That works, but a loot of lines of repetive code if you have say, 15 posible property classes. I have investigated Reflection and dynamic types but found nothing, can you help me? Thanks for your time, I hope I gave a nice explanation.
Upvotes: 0
Views: 83
Reputation: 86650
Your code is very confusing, so, my answer code is not the very best as well, but if you understand your code, you can understand the answer.
The first approach I would try is generics:
First make some abstract value get, set in the root classes:
public abstract class RootValue
{
public RootProperty Property {get;set;}
public abstract object ValueInRoot {get; set;}
}
public abstract class RootDto
{
public int PropertyId {get; set; }
public abstract object ValueInRoot {get; set; }
}
Since you create new AProperty in your last method, I believe it also inherits RootProperty, so, RootProperty should follow the above idea as well. But I believe you will find out that Property class might not be needed. (See comments in ValueClass)
Id suggest RootProperty had a CreateValue
method:
public abstract class RootProperty
{
public int Id {get; set;}
public abstract RootValue CreateValue();
}
Where you have AProperty through ZProperty, use a single class declaration like this.
It's a generic class, takes a type parameter (TValue
), wich is not known at compile time.
//I really believe the properties are inheriting RootProperty
public class Property<TValue> : RootProperty
{
public ValueClass<TValue> CreateTypedValue()
{
//Create the new ValueClass<TValue> here;
//I believe it's the best place to do that.
//It will know the type and it can be called via the
//overriden method below
//This way you avoid calling the Value contructor in your
//final method.
}
public override RootValue CreateValue()
{
return this.CreateTypedValue();
}
}
Where you have AValue throug ZValue, use this, overriding that Root value: (Beware, since I don't know how you use the Property here, take a look at the comments in constructor to see the idea)
public class ValueClass<TValue> : RootValue
{
//this line is not clear for me....
public ValueClass(Property<TValue>)
{
//I believe you should leave the task of creating this ValueClass to the
//Property CreateTypedValue() method.
//See that I added the CreateValue in te property classes,
//you will see further on why I did that. It solves constructor problem.
}
public TValue Value {get; set;}
public override object ValueInRoot
{
get { return Value; }
set { Value = (TValue)value; }
}
}
For the domain:
public class DomainProperty<TValue>
{
public ICollection<TValue> Domain {get; set;}
}
public class DomainValue<TValue>
{
public DomainValue(DomainProperty<TValue>) {...}
public TValue Value
{
set {
//Here I'd use Domain.Contains(value)
if (!this.Property.Domain.Any(d=>d==value))
{
throw new Exceptin("Value out of range!");
}
}
}
}
For the DTOs, that also overrides the root value:
public class Dto<TValue> : RootDto
{
public TValue Value {get; set;}
public override object ValueInRoot
{
get { return Value; }
set { Value = (TValue)value; }
}
}
And finally, your assign method on server:
foreach(dto in listDtio)
{
//if (someDto is ADto)
//{
//ADto castedDto = (ADto) dto;
RootProperty dtoProperty = Repository.findRootProperty(dto.PropertyId);
//here is the way you solve your constructor problem.
RootValue valueForDto = dtoProperty.CreateValue();
//and here you assign values without knowing their types,
//but they will still be typed
valueForDto.ValueInRoot = dto.ValueInRoot;
//}
//if ...(B.....Z)
}
Upvotes: 2
Reputation: 505
To give a start: I would say that some possible solution is iterate in constructors of all classes extending from RootValue, find some with a XProperty argument, call it, and asign Value dynamically
Upvotes: 0