2009-08-17 1 views
3

Я пишу систему, которая имеет набор буферов протокола (с использованием Protobuf сети), я хочу, чтобы определить что-то вроде этого в абстрактном классе они все унаследует от:C# универсальный тип в базовом классе

public byte[] GetBytes() 

однако, для буфера serealiser протокола требуется аргумент типа, есть ли эффективный способ получить тип наследующего класса?

Пример:

public byte[] GetBytes() 
    { 
     using (MemoryStream stream = new MemoryStream()) 
     { 
      Serializer.Serialize<T /* what goes here? */>(stream, this); 
      return stream.ToArray(); 
     } 
    } 
+0

Ну, это было неловко просто;) – Martin

+0

Это даст вам базовый класс для всех экземпляров, если вы не измените каждый производный класс индивидуально (не уверен, что это то, что вы хотите, или нет). Есть причина, по которой protobuf.net добавил не общую версию, используя отражение ... –

+0

Там, сделал это. Напротив автора C# в двух словах не меньше. : P –

ответ

4

Просто написать "T" правильный?

, а затем в вашем объявлении класса:

public class M<T> 

?

- Edit

И тогда, когда вы унаследовали его:

public class Foo : M<Apple> 
3

Определите базовый класс как BaseClass<T>, а затем ваши производные классы заменить Т с типом сериализатора DerivedClass<SerializerType>.

Вы также можете указать ограничения на аргумент типа, например.

BaseClass<T> where T : SerializerBase 

Here является описание типов ограничений, которые можно применить.

3

Вы можете сделать это с помощью отражения, но protobuf-net сделал это для вас.

Просто измените вызов:

Serializer.NonGeneric.Serialize(stream, this /* Takes an object here */); 

Это работает путем создания универсального метода во время выполнения с помощью отражения. Подробнее см. Код (second method here).

+0

Как быстро это? Я слышал, что отражение довольно медленное, и я использую это для сериализации сетевых пакетов в игре, поэтому, если это не так быстро, это не достаточно хорошо;) – Martin

+0

Отражение определенно добавляет некоторые накладные расходы (хотя, вероятно, это меньше, чем скорость вашего сетевого пакета, поэтому он может не важно). Прочитайте это, чтобы рассказать. Вы можете отредактировать свои классы, как упоминание в ответе Silky, что даст лучший перфоманс, но потребует от вас всех ваших классов, которые вы хотите сериализовать родовыми, просто для обеспечения «T». Это может быть хорошо, но это не прямой ответ на ваш оригинальный вопрос, так как это изменение в структуре иерархии классов. Это может вызвать проблемы, если у вас уже есть другой базовый класс. –

1

Вам не нужно ничего особенного здесь ... поскольку protobuf-net уважает наследование. Если у вас есть:

[ProtoInclude(typeof(Foo), 20)] 
[ProtoInclude(typeof(Bar), 21)] 
public abstract class MyBase { 
    /* other members */ 

    public byte[] GetBytes() 
    { 
     using(MemoryStream ms = new MemoryStream()) 
     { 
      Serializer.Serialize<MyBase>(ms, this); // MyBase can be implicit 
      return ms.ToArray(); 
     } 
    } 
} 
[ProtoContract] 
class Foo : MyBase { /* snip */ } 
[ProtoContract] 
class Bar : MyBase { /* snip */ } 

тогда это сработает. Для сериализации данных он всегда начинается с основания (контракта) типа; так что даже если вы сделали Serializer.Serialize<Foo>(stream, obj), первое, что он сделает, это обнаружить, что у него есть базовый класс, который является контрактом, и переключиться на MyBase. Во время десериализации он идентифицирует правильный производный (конкретный) тип и использует его, поэтому вы можете использовать Deserialize с MyBase, и он будет строить Foo или Bar в зависимости от исходных данных.

Таким образом, следующие в основном идентичны:

Serializer.Serialize<BaseType>(dest, obj); 
... 
BaseType obj = Serializer.Deserialize<BaseType>(source); 

и

Serializer.Serialize<DerivedType>(dest, obj); 
... 
DerivedType obj = Serializer.Deserialize<DerivedType>(source); 

Основное различие в том, как переменные набираются.

+0

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

+0

Не быстрее или медленнее. Он всегда должен вернуться на базу и работать вперед. –

+0

О, хорошо, отлично. Как в стороне, вы бы рекомендовали использовать буферы протокола для сериализации сетевых пакетов в игре? – Martin

 Смежные вопросы

  • Нет связанных вопросов^_^