приведение к нескольким (неизвестные типы) во время выполнения - PullRequest
1 голос
/ 06 марта 2009

Я разрабатываю программу просмотра, которая сможет открывать все пользовательские документы, которые мы создаем с помощью нашего программного обеспечения. Все документы наследуются от IDocument, но я не уверен, как выполнить десериализацию (в хорошем смысле - вложенный try / catch может, вероятно, работать, но это будет отвратительно).

Итак, мой метод, как он выглядит сейчас, выглядит так:

public Boolean OpenDocument(String filename, Type docType, out IDocument document)
{
    // exception handling etc. removed for brevity

    FileStream fs = null;
    BinaryFormatter bFormatter = new BinaryFormatter();

    fs = new FileStream(filename, FileMode.Open);
    document = (docType)bFormatter.Deserialize(fs);

    return true;
}

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

edit> @John хорошо, возможно я должен добавить другой вопрос: если у меня есть интерфейс:

public interface IDocument
{
    public Int32 MyInt { get; }
}

и класс:

public class SomeDocType : IDocument
{
    protected Int32 myInt = 0;
    public Int32 MyInt { get { return myint; } }

    public Int32 DerivedOnlyInt;
}

если я десериализую в IDocument, будет ли DerivedOnlyInt быть частью объекта - таким образом, что после десериализации я могу привести к SomeDocType, и все будет хорошо?

Ответы [ 3 ]

4 голосов
/ 06 марта 2009

Почему бы просто не привести к IDocument? Как вы думаете, какое преимущество принесет приведение к точному типу?

Если вы хотите, чтобы вызывающий получал результат строго типизированным способом, вот как я бы написал его, используя дженерики:

public T OpenDocument<T>(String filename) where T : IDocument
{
    using (FileStream fs = new FileStream(filename, FileMode.Open))
    {
        BinaryFormatter bFormatter = new BinaryFormatter();    
        return (T) bFormatter.Deserialize(fs);
    }
}

Конечно, это полагается на то, что вызывающая сторона знает правильный тип во время компиляции. Если они этого не сделают, они никак не узнают, как использовать правильный тип в любом случае, поэтому просто верните IDocument:

public IDocument OpenDocument(String filename)
{
    using (FileStream fs = new FileStream(filename, FileMode.Open))
    {
        BinaryFormatter bFormatter = new BinaryFormatter();    
        return (IDocument) bFormatter.Deserialize(fs);
    }
}

РЕДАКТИРОВАТЬ: Чтобы ответить на редактирование вашего вопроса, да, производное свойство все еще существует. Кастинг на самом деле не меняет объект - он просто означает, что вы получаете ссылку, которая, как знает компилятор, имеет соответствующий тип.

1 голос
/ 06 марта 2009

Если вы можете легко выяснить, что это за документ (то есть: он является частью заголовка файла), возможно, проще всего будет иметь стратегию для десериализации, специфичную для каждого типа.

1 голос
/ 06 марта 2009

Вы используете класс BinaryFormatter, который включает информацию о типе в сериализованный поток, поэтому вам не нужна переменная docType:

public Boolean OpenDocument(String filename, out IDocument document)
{
    // exception handling etc. removed for brevity

    FileStream fs = null;
    BinaryFormatter bFormatter = new BinaryFormatter();

    fs = new FileStream(filename, FileMode.Open);
    document = (IDocument)bFormatter.Deserialize(fs);

    return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...