我的情况是:我有代表属性的类:
public abstract class RootProperty {
public int Id {get; set;}
}
public class AProperty {}
public class BProperty {}
,让这里有一大堆这样的东西:
public class ZProperty {}
以及每个属性的值
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;} }
实际上,每个类都代表了一个事物必须具有的属性类型。所以如果我想说一个属性是由字符串定义的它必须在给定的域中有值我说:
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!");
}
}
}
}
所以我可以狗可以小或大,我的是大。
DomainProperty DogsSize = new DomainProperty { Domain= ["big","small"] }
DomainValue MyDogSize = new DomainValue(color) { Value = "big" }
使用这个,我可以定义具有最大值和最小值等数值范围的属性。好的,这里的第一个问题是:你能想到其他解决方案来解决可定制属性类型的问题吗?
现在,让我在这里发布的问题:前面的逻辑在服务器端,它从客户端接收一个抽象数据列表:
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; } }
与RootDto PropertyId我可以找到原来的RootProperty。我想创建一个?Value的新实例,并将值设置为?Dto.Value。现在我在很多类型转换中都有这个:
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)
}
这是可行的,但是如果你有15个可能的属性类,就会有很多行重复的代码。我已经调查了反射和动态类型,但没有发现,你能帮助我吗?谢谢你的时间,我希望我给了一个很好的解释。
你的代码很混乱,所以,我的答案代码也不是最好的,但是如果你理解你的代码,你就能理解答案。
我尝试的第一种方法是泛型:
首先在根类中设置一些抽象值:
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; }
}
因为你在上一个方法中创建了新的AProperty,我相信它也继承了RootProperty,所以,RootProperty也应该遵循上面的想法。但是我相信您会发现Property类可能并不需要。(参见ValueClass中的注释)我建议RootProperty有一个CreateValue
方法:
public abstract class RootProperty
{
public int Id {get; set;}
public abstract RootValue CreateValue();
}
如果你有一个property到ZProperty,使用像这样的单个类声明。它是一个泛型类,接受一个类型参数(TValue
),该参数在编译时是未知的。
//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();
}
}
如果你有value通过ZValue,使用这个,覆盖根值:(注意,因为我不知道你如何在这里使用属性,看看构造函数中的注释来了解这个想法)
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; }
}
}
对于域:
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!");
}
}
}
}
对于dto,这也覆盖了根值:
public class Dto<TValue> : RootDto
{
public TValue Value {get; set;}
public override object ValueInRoot
{
get { return Value; }
set { Value = (TValue)value; }
}
}
最后,服务器上的assign方法:
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)
}
首先:我会说一些可能的解决方案是迭代所有类的构造函数从RootValue扩展,找到一些与XProperty参数,调用它,并动态赋值