在编译时类调用未知的构造函数

时间:2013-06-05 20:27:44

标签: c#-4.0 generics dynamic reflection

这是我的情况: 我有代表属性的类:

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" }

使用这个,我可以定义具有最大值和最小值等的数值范围的属性.Okey,这里的第一个问题是:你能想到一些其他解决方案可以解决这个类似于coustomizable属性的问题吗?

现在,让我在这里发帖的问题: 以前的逻辑是在服务器端,它从客户端返回一个抽象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; } }

使用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个有形的属性类,那就是一堆重复代码。 我调查了反射和动态类型但没有发现任何东西,你能帮帮我吗? 谢谢你的时间,我希望我能给出一个很好的解释。

2 个答案:

答案 0 :(得分:2)

您的代码非常混乱,因此,我的答案代码也不是最好的,但如果您了解代码,则可以理解答案。

我会尝试的第一种方法是泛型:

首先在根类中设置一些抽象值get:

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();
}

如果您通过ZProperty拥有AProperty,请使用这样的单个类声明。 它是一个泛型类,带有一个类型参数(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();
    }
}

如果您通过ZValue获得AValue,请使用此值,覆盖该Root值: (请注意,因为我不知道你如何使用这里的属性,看看构造函数中的注释,看看这个想法)

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)
}

答案 1 :(得分:0)

开始: 我想说一些可能的解决方案是在从RootValue扩展的所有类的构造函数中迭代,找到一些带有XProperty参数,调用它,并动态地赋值值