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

时间:2010-07-06 16:35:03

标签: c# asp.net inheritance

我将拥有一个对象的多个“类型”,我真的不确定如何最好地检索/保存这些多种类型而不需要为每种类型单独保存/检索。

我的课程:

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

获取/保存方法内部:

// 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 个答案:

答案 0 :(得分:4)

试试这个

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

}

然后你可以拥有一个ISaveable集合,例如List<ISaveable>,并在每个上面调用SaveFields,无论类型如何。您现在正在针对接口进行编程,而不是针对具体类型。解决代码的第一步。

已编辑:回复您的评论 在您的存储库中,您将不再针对Evaluation类进行编程。相反,你会再次编程它实现的接口中的方法:

而不是:

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

答案 1 :(得分:1)

你的问题不清楚,仍然从我的理解,你正在寻找对象的类型。这是你如何做到的。

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

如果您需要基类/父类中的子类类型,请按以下方式更新您的Evaluation类。

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

答案 2 :(得分:1)

这听起来非常适合泛型,很多存储库和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
{
}

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

答案 3 :(得分:0)

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.

答案 4 :(得分:0)

我将您的问题解释为询问调度自定义保存逻辑的便捷方式,而不会对子对象的类型进行“杂乱”切换。如果你想要的只是一种简单的方法来输入参数,你可以使用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方法如何具有相同的名称,但它们的参数类型只是重载。 dynamic方法中使用的SaveEvaluation参数将在运行时进行评估,并调度到适当的重载。

答案 5 :(得分:0)

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

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

也许你也可以使基类抽象化。此外,您通常应该避免将字段公开访问 - 这可能会将代码保持为噩梦,因此我在示例中使用了属性。