代码之家  ›  专栏  ›  技术社区  ›  Dan

从C中的父类参数获取子类类型#

  •  4
  • Dan  · 技术社区  · 15 年前

    我将拥有一个对象的多个“类型”,我真的不知道如何最好地检索/保存这些多个类型,而不必为每种类型分别进行保存/检索。

    我的班级:

    public class Evaluation {
      public int Id
      public string Comment
    }
    
    public class EvaluationType_1 : Evaluation {
      public string field
    }
    
    public class EvaluationType_1 : Evaluation {
      public string field
    }
    

    我想在我的存储库中执行的操作:

    public interface IEvaluationRepository {
      public Evaluation getEvaluation(int id);
      public SaveEvaluation(Evaluation);
    }
    

    在get/save方法中:

    // Save/get common fields
    Id
    Comments
    
    // Get child type, perform switch
    Type childType = ???
    switch(childType) {
      // Set child-specific fields
    }
    

    我希望这是有道理的。我不想添加一个“类型”列,因为我在数据库的另一部分中有这个列,而且我不太喜欢它。

    更新

    大家好,谢谢。如有必要,这里有更多信息/问题需要澄清。

    我喜欢使用接口和泛型的想法,我真的对如何将它们合并到我的存储库模式中感到茫然。

    当我呼唤 getEvaluation ,我希望它返回一个抽象的评估,但我正在努力处理这段代码。节约也是一样-任何有关这方面的见解都会很好-再次感谢!

    更新2

    我不想继续改进这一点,但丹尼尔正在帮助我仔细研究我到底想问什么:P。

    笪塔巴涩: 评价 ID(PK) 评论

    EvaluationType1
      Id (FK to Evaluations.Id)
      Field
    
    EvaluationType1
      Id (FK to Evaluations.Id)
      Field
    

    所以,在 getEvaluation(int id) 我需要弄清楚他们想要什么类型的评估。这是否意味着我应该通过一个类型?同样的道理 saveEvaluation 但是我可以做一个开关/功能图来看看 Type 它是。

    6 回复  |  直到 15 年前
        1
  •  4
  •   Daniel Dyson    15 年前

    试试这个

    public interface ISaveable {
       void SaveFields();
    }
    
    public abstract class Evaluation : ISaveable {
      public int Id
      public string Comment
    
      public virtual void SaveFields() {
         //Save ID and Comments
      }
    }
    
    public class EvaluationType_1 : Evaluation {
        public string field1
    
      public override void SaveFields() {
         //Save field1
         base.SaveFields();
      }
    
    }
    
    public class EvaluationType_2 : Evaluation {
       public string field2
    
      public override void SaveFields() {
         //Save field2
         base.SaveFields();
      }
    
    }
    

    然后您可以收集一些可共享的,例如 List<ISaveable> 并对每一个调用savefields, 不管 它们的类型。您现在是针对接口而不是针对具体类型进行编程的。实现代码分离的第一步。

    编辑: 回应你的评论 在您的存储库中,您将不再针对评估类进行编程。相反,您将重新编程它实现的接口中的方法:

    而不是:

    public interface IEvaluationRepository {
      public Evaluation getEvaluation(int id);
      public SaveEvaluation(Evaluation);
    }
    

    你可能有:

     public interface ISaveableRepository {
       public ISaveable getSavable(int id);
       public Save(ISaveable saveable);
     }
    

    存储库的实现可能类似于:

     public class SaveableEvaluationRepository : ISaveableRepository {
       public ISaveable getSavable(int id) {
           //Add your logic here to retrieve your evaluations, although I think that 
           //this logic would belong elsewhere, rather than the saveable interface.
       }
    
       public Save(ISaveable saveable) {
           saveable.SaveFields();
       }
     }
    
        2
  •  1
  •   this. __curious_geek    15 年前

    你的问题还不清楚,但根据我的理解,你在寻找物体的类型。这是你的做法。

    EvaluationType_1 objOfEvalType1 = new EvaluationType_1();
    Type childType = objOfEvalType1.GetType();
    

    如果需要基类/父类中的子类类型,请按如下所示更新评估类。

    public class Evaluation {
      public int Id;
      public string Comment;
    
      //call this.GetType() anywhere you wish to get the type of the object.
      public Type MyType = this.GetType();
    }
    
        3
  •  1
  •   Cylon Cat    15 年前

    这听起来是一个非常好的泛型候选,许多存储库和ORM框架都使用它们。

    public interface IEvaluationRepository<TEvaluation> 
    { 
      public TEvaluation getEvaluation(int id); 
      public SaveEvaluation(TEvaluation evaluation); 
    } 
    

    您可能还需要一个EvaluationBase类来处理公共函数,并将您的接口约束为只接受EvaluationBase类:

    public interface IEvaluationRepository<TEvaluation> where TEvaluation : EvaluationBase
    ...
    public class SomeEvaluation : EvaluationBase
    {
    }
    

    它可以节省识别和跟踪对象类型的大部分或全部问题。

        4
  •  0
  •   Jeff Sternal    15 年前

    Object.GetType 返回当前实例的确切运行时类型-它不考虑关联变量的声明类型:

    Type type = evaulation.GetType();
    
    // Note that you can't switch on types
    
    if (type == typeof(DerivedEvaluation1)) {
        // Perform custom operations        
    }
    else if (type == typeof(DerivedEvaluation2)) {
        // Perform custom operations
    }
    
    // Etc.
    
        5
  •  0
  •   LBushkin    15 年前

    我将您的问题解释为询问如何在不“混乱”地打开子对象类型的情况下发送自定义保存逻辑。如果您只需要一种简单的方法来gt类型A参数,则可以使用 is 关键字。

    有几种基于运行时类型的调度逻辑方法。

    一个是你可以创建一个调度字典 Save 每种特定类型的功能:

    private static readonly Dictionary<Type,Action<Evaluation>> s_SaveFunctions =
        new Dictionary<Type,Action<Evaluation>>();
    
    s_SaveFunctions[typeof(ChildA)] = SaveChildA;
    s_SaveFunctions[typeof(ChildB)] = SaveChildB;
    // .. and so on.
    
    public SaveEvaluation( Evaluation eval )
    {
       // .. common save code ...
    
       // cal the appropriately typed save logic...
       s_SaveFunctions[eval.GetType()]( eval );
    }
    
    private static void SaveChildA( Evaluation eval ) { ... }
    
    private static void SaveChildB( Evaluation eval ) { ... }
    

    在.NET 4中,您可以使用 dynamic 要实现更清晰的版本:

    public SaveEvaluation( Evaluation eval )
    {
       // .. common save logic ..
    
       dynamic evalDyn = eval;
    
       SaveChild( evalDyn );
    }
    
    private void SaveChild( ChildA eval ) { ... }
    
    private void SaveChild( ChildB eval ) { ... }
    

    注意如何 SaveChild 方法都具有相同的名称,但只是由其参数的类型重载。这个 动态 中使用的参数 SaveEvaluation 方法将在运行时进行计算,并发送到适当的重载。

        6
  •  0
  •   Daniel Brückner    15 年前

    您可以将方法设置为虚拟的-调用将根据实际的运行时类型调度到正确的方法。

    public class Evaluation
    {
        public Int32 Id { get; set; }
        public String Comment { get; set; }
    
        public virtual void Save()
        {
            // Save the common information.
            this.SaveToDatabase(this.Id);
            this.SaveToDatabase(this.Comment);
        }
    
        private void SaveToDatabase(Object value)
        {
            // Left as an exercise for the reader... :D
        }
    }
    
    public class EvaluationType1 : Evaluation
    {
        public String Foo { get; set; }
    
        public override void Save()
        {
            // Save the common information.
            base.Save();
    
            // Save the specific information here.
            this.SaveToDatabase(this.Foo);
        }
    }
    
    
    public class EvaluationType2 : Evaluation
    {
        public String Bar { get; set; }
    
        public override void Save()
        {
            // Save the common information.
            base.Save();
    
            // Save the specific information here.
            this.SaveToDatabase(this.Bar);
        }
    }
    

    也许您也可以将基类抽象化。此外,您通常应该避免将字段公开,这可能会将维护代码变成一场噩梦,因此我在示例中使用了属性。