Получение типа дочернего класса из параметра родительского класса в C # - PullRequest
4 голосов
/ 06 июля 2010

У меня будет несколько «типов» объекта, и я действительно не уверен, как лучше извлечь / сохранить эти несколько типов без отдельного сохранения / извлечения для каждого типа.

Мои классы:

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.

База данных: Идентификатор оценки (PK) Комментарий

EvaluationType1
  Id (FK to Evaluations.Id)
  Field

EvaluationType1
  Id (FK to Evaluations.Id)
  Field

Итак, в getEvaluation(int id) мне нужно выяснить, какой тип оценки онихочу.Означает ли это, что я должен передать тип?То же самое верно в saveEvaluation, но я могу сделать карту переключателей / функций, чтобы увидеть, что это такое Type.

Ответы [ 6 ]

4 голосов
/ 06 июля 2010

Попробуйте это

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 голос
/ 06 июля 2010

Звучит как очень хороший кандидат на дженерики, и многие репозитории и 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
{
}

Это избавит от большинства или всех проблем распознавания и отслеживания типов объектов.

1 голос
/ 06 июля 2010

Ваш вопрос неясен, все же из того, что я понял, вы ищете тип объекта.Вот как вы это делаете.

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();
}
0 голосов
/ 06 июля 2010

Вы можете просто сделать ваши методы виртуальными - вызов будет отправлен на правильный метод, основанный на фактическом типе времени выполнения.

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

Возможно, вы также можете сделать базовый класс абстрактным. Кроме того, обычно вы должны избегать публичного доступа к полям - это может превратить поддержание кода в кошмар, и поэтому я использую свойства в своем примере.

0 голосов
/ 06 июля 2010

Я интерпретирую ваш вопрос как вопрос об удобном способе отправки настраиваемой логики сохранения без «грязного» переключения типа дочернего объекта.Если все, что вам нужно, это простой способ ввести параметр, вы можете использовать ключевое слово 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, будет оцениваться во время выполнения и отправляться с соответствующей перегрузкой.

0 голосов
/ 06 июля 2010

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...