Как получить все типы наследующих класс во время компиляции? - PullRequest
1 голос
/ 18 декабря 2011

Я пытаюсь написать сетевой код, который автоматически сериализует и десериализует пакет в NetworkMessage.

Вот код для NetworkMessage

public abstract class NetworkMessage : ISerializable
{
    public readonly NetworkClient Client;

    protected NetworkMessage(NetworkClient client)
    {
        this.Client = client;
    }

    public abstract void GetObjectData(SerializationInfo info, StreamingContext context);
}

А вот коддля образца NetworkMessageText

public class NetworkMessageText : NetworkMessage
{
    public static readonly Byte Id = 0x01;

    public readonly String Message;

    public NetworkMessageText(NetworkClient client, String message)
        : base(client)
    {
        this.Message = message;
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("message", this.Message, typeof(String));
    }
}

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

Это класс NetworkMessagesIds, который делает это для меня

public static class NetworkMessageIds
{
    private static readonly Dictionary<Type, Byte> TypeIdDictionary = new Dictionary<Type, Byte>();
    private static readonly Dictionary<Byte, Type> IdTypeDictionary = new Dictionary<Byte, Type>(); 

    static NetworkMessageIds()
    {
        TypeIdDictionary.Add(typeof(NetworkMessageText), NetworkMessageText.Id);
        IdTypeDictionary.Add(NetworkMessageText.Id, typeof(NetworkMessageText));
    }

    public static Byte IdFromType(Type type)
    {
        return TypeIdDictionary[type];
    }

    public static Type TypeFromId(Byte id)
    {
        return IdTypeDictionary[id];
    }
}

То, что я ищу, это способавтоматически генерировать байт Id для каждого класса, который наследует NetworkMessage во время компиляции.Я мог бы сделать это во время выполнения, используя Reflection, но тогда я не знаю, могу ли я доверять, чтобы идентификаторы были одинаковыми каждый раз для каждой машины, и использование Reflection кажется немного чрезмерным для чего-то подобного.

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

1 Ответ

3 голосов
/ 18 декабря 2011

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

var knownMessageTypes = AppDomain.CurrentDomain.GetAssemblies().ToList().ForEach(a => a.GetTypes().ToList().Where(t => t.IsSubclassOf(typeof(NetworkMessage)));

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

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple=false)]
public class NetworkMessageAttribute : Attribute
{
    public byte MessageID { get; set }
}

Затем вы можете создать сетевой тип сообщения следующим образом:

[NetworkMessage(MessageID = 0x01)]
public class ExampleNetworkMessage : NetworkMessage

Я успешно использовал эту общую концепцию дизайнав нескольких различных проектах.


РЕДАКТИРОВАТЬ: Если вы действительно хотите достичь своей цели в том виде, в котором она была разработана выше, это может быть достигнуто с помощью подхода, аналогичного приведенному выше коду.Просто поместите его в консольное приложение, которое сгенерирует файл списка определений сообщений, который будет прочитан вашим приложением, и настройте его как действие после сборки в вашем проекте.

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