Способ приведения базового типа к производному типу - PullRequest
43 голосов
/ 24 сентября 2008

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

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

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

Ответы [ 17 ]

0 голосов
/ 24 сентября 2008

Это называется унынием, и предложение Селдака использовать «безопасную» версию вполне обоснованно.

Вот довольно приличное описание с примерами кода .

0 голосов
/ 21 августа 2014

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

Однако, в вашем случае, 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>();

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

0 голосов
/ 24 сентября 2008

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

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

0 голосов
/ 24 сентября 2008

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

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

0 голосов
/ 13 марта 2012

Недавно я нуждался в расширении простого 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.

0 голосов
/ 24 января 2012

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

0 голосов
/ 14 января 2010

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

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

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

...