【问题标题】:Calling a constructor of a unknowed at compile time class在编译时调用未知类的构造函数
【发布时间】:2013-06-01 16:50:09
【问题描述】:

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

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

使用它,我可以定义具有最大值和最小值等数值范围的属性。好吧,这里的第一个问题是:对于这个可定制类型的属性问题,你能想出其他解决方案吗?

现在,让我在这里发帖的问题: 前面的逻辑在服务器端,它从客户端接收一个抽象 dto 列表:

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 个可能的属性类的话,会产生大量重复代码。 我调查了反射和动态类型,但一无所获,你能帮帮我吗? 感谢您的宝贵时间,希望我给了一个很好的解释。

【问题讨论】:

    标签: c#-4.0 generics dynamic reflection


    【解决方案1】:

    你的代码很混乱,所以,我的答案代码也不是最好的,但是如果你理解你的代码,你就可以理解答案。

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

    首先获取一些抽象值,设置在根类中:

    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 中的 cmets) 我建议 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 值: (注意,这里的Property我不知道你是怎么用的,看一下constructor中的cmets就知道思路了)

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

    最后,你在服务器上的分配方法:

    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- 属性创造了价值。 2- 由于所有 Value 类都具有相同的 Value 属性,因此使其成为根上的抽象属性。感谢您的宝贵时间,我学到了一些新东西:D
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2020-02-24
      • 2011-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多