Подтвердить что ты не робот

Способ литья базового типа в производный тип

Я не уверен, что это странная вещь, или нет, или если это какой-то запах кода... но мне было интересно, есть ли способ (какой-то образец oop был бы приятным) "лить" базовый тип в форму его производного типа. Я знаю, что это имеет мало смысла, поскольку производный тип будет иметь дополнительную функциональность, которую родитель не предлагает, которая сама по себе не имеет принципиально правильного звучания. Но есть ли способ сделать это? Вот пример кода, поэтому я могу лучше объяснить, что я прошу.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

Я знаю, что это кажется глупым, но есть ли способ сделать что-то подобное?

4b9b3361

Ответ 1

Неплохо, на "управляемых" языках. Это опускание, и нет никакого разумного способа справиться с этим, именно по той причине, которую вы описали (подклассы предоставляют больше, чем базовые классы - откуда это "больше"?). Если вы действительно хотите аналогичное поведение для определенной иерархии, вы можете использовать конструкторы для производных типов, которые будут использовать базовый тип в качестве прототипа.

Можно было построить что-то с отражением, которое обрабатывало простые случаи (более конкретные типы, у которых нет состояния добавления). В общем, просто перепроектируйте, чтобы избежать проблемы.

Изменить: Woops, не может записывать операторы преобразования между базовыми/производными типами. Странность Microsoft пытается "защитить вас" от вас самих. Ах, ну, по крайней мере, они не такие, как солнце, как солнце.

Ответ 2

Попробуйте композицию вместо наследования!

Мне кажется, что вам лучше передать экземпляр SomeBaseClass в SomeDerivedClass (который больше не будет выводить базовый класс и должен быть переименован как таковой)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

Отъезд http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html (стр. 3):

Повторное использование кода с помощью композиции Состав предоставляет альтернативный способ для Apple для повторного использования отслаивание(). Вместо того, чтобы распространять фрукты, Apple может содержать ссылку на фрукты экземпляр и определить его собственную кожуру() метод, который просто вызывает peel() on Фрукты.

Ответ 3

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

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}

Ответ 4

Downcasting имеет смысл, если у вас есть объект производного класса, но он ссылается на ссылку типа базового класса и по какой-то причине вы хотите, чтобы на него ссылались ссылки на производный тип. Другими словами, вы можете понизить, чтобы изменить эффект предыдущего повышения. Но у вас не может быть объекта базового класса, на который ссылается ссылка типа производного класса.

Ответ 5

Я не говорю, что рекомендую это. Но вы можете превратить базовый класс в строку JSON, а затем преобразовать его в производный класс.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));

Ответ 6

Нет, это невозможно. На управляемом языке, таком как С#, это просто не сработает. Время выполнения не позволит этого, даже если компилятор пропускает его.

Ты сам сказал, что это кажется глупым:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

Так спросите себя, есть ли class экземпляр SomeDerivedClass? Нет, поэтому преобразование не имеет смысла. Если вам нужно преобразовать SomeBaseClass в SomeDerivedClass, тогда вы должны предоставить какое-то преобразование, либо конструктор, либо метод преобразования.

Звучит так, как будто ваша иерархия классов нуждается в некоторой работе. В общем случае не должно быть возможности конвертировать экземпляр базового класса в экземпляр производного класса. Обычно должны быть данные и/или функциональные возможности, которые не относятся к базовому классу. Если функциональность производного класса применяется ко всем экземплярам базового класса, то она должна либо сворачиваться в базовый класс, либо входить в новый класс, который не является частью иерархии базового класса.

Ответ 7

Язык С# не разрешает такие операторы, но вы все равно можете их записать и они работают:

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }

Ответ 8

Да - это запах кода, и в значительной степени устраняет тот факт, что цепочка наследования повреждена.

Мое предположение (из ограниченного примера) заключается в том, что вы бы предпочли, чтобы DerivedClass работал с экземпляром SomeBaseClass, так что "DerivedClass имеет SomeBaseClass", а не "DerivedClass - это SomeBaseClass". Это известно как "предпочтительная композиция над наследованием".

Ответ 9

Как отмечали другие, кастинг, который вы предлагаете, на самом деле невозможен. Может быть, это может быть случай, когда можно ввести Decorator pattern (Head First extract)?

Ответ 10

Задумывались ли вы о интерфейсе, что бы реализовать ваш базовый класс и ваш производный класс? Я не знаю специфики того, почему вы реализуете этот способ, но он может работать.

Ответ 11

Это не сработает. Перейдите на страницу справки, связанную с ошибкой компиляции.

Лучшее решение - использовать здесь методы factory.

Ответ 12

Это называется downcasting, и предложение Seldaek использовать "безопасную" версию звучит.

Здесь довольно приличное описание с образцами кода.

Ответ 13

Это невозможно, потому что как вы собираетесь получить "лишний", который имеет производный класс. Как компилятор знает, что вы подразумеваете производный класс1, а не производныйClass2, когда вы его создаете?

Я думаю, что вы действительно ищете шаблон factory или похожий, чтобы вы могли создавать объекты, не зная явного типа, который создается. В вашем примере метод "Вставка" будет интерфейсом, который возвращает экземпляр factory.

Ответ 14

Я не знаю, почему никто не сказал это, и я, возможно, что-то пропустил, но вы можете использовать ключевое слово as, и если вам нужно использовать оператор if, если.

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-edit- Я задал этот вопрос давно

Ответ 15

Недавно мне было необходимо расширить простой DTO с производным типом, чтобы добавить на него еще несколько свойств. Затем я хотел повторно использовать некоторую логику преобразования, которую я использовал, от внутренних типов баз данных до DTO.

То, как я решил это, было принудительным пустым конструктором классов DTO, используя его следующим образом:

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

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

Ответ 16

Как и многие ответы, вы не можете понизить, что делает полный смысл.

Однако в вашем случае SomeDerivedClass не имеет свойств, которые будут отсутствовать. Таким образом, вы можете создать метод расширения следующим образом:

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

Итак, вы не кастинг, просто конвертируете:

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

Это действительно работает, только если все данные в базовом классе находятся в форме читаемых и записываемых свойств.

Ответ 17

С++ обрабатывает его с помощью конструктора. С++ Typecasting. Мне кажется, что это недосмотр. Многие из вас затронули вопрос о том, что будет делать процесс с дополнительными свойствами. Я бы ответил, что делает компилятор, когда он создает производный класс, когда программист не устанавливает свойства? Я справился с этой ситуацией, подобной С++. Я создаю конструктор, который принимает базовый класс, а затем вручную устанавливает свойства в конструкторе. Это определенно предпочтительнее устанавливать переменную в производном классе и нарушать наследование. Я бы также выбрал его по методу factory, потому что я думаю, что полученный код будет более чистым.