Как создать новое static поле в наследнике или КАК СЭКОНОМИТЬ пару байт?
У меня имеется класс Packet, от которого наследуются другие Packet'ы.
public abstract class Packet
{
public static byte Id;
public virtual void Write(ref RawPacket packet)
{
packet.WriteByte(Id);
}
}
Как сделать так чтобы для каждого наследника этого класса был свой static Id, чтобы сэкономить пару байт? Пытался выносить Id в Static Generic классы, но тогда метод Write не видит Id.
Например у меня имеется PacketA, PacketB, которые наследуются от класса Packet. И ко мне по сети приходит массив байт, первый элемент которого указывает на тип пакета, то есть Id. И с помощью Id, используя Dictionary<byte, Type> я могу обратится к экземпляру класса PacketA или B и узнать каким способом считывать этот массив. А экземпляры пакетов PacketA, PacketB очень часто создаются, потому Id в экземплярах одних и тех же PacketA или PacketB будут расходовать лишний байт памяти на каждое Id.
Ответы (3 шт):
Можно вместо статики прописать в базовом классе абстрактное свойство:
public abstract class Packet
{
public abstract byte Id
{
get;
}
public virtual void Write (ref RawPacket packet)
{
packet.WriteByte(Id);
}
}
И имплементировать это свойство в производных классах:
public class PacketA : Packet
{
public override byte Id => 1;
}
public class PacketB : Packet
{
public override byte Id => 2;
}
Вам нужно объявлять Id в каждом наследнике:
public class PacketA : Packet
{
public static byte Id;
public override void Write(ref RawPacket packet)
{
packet.WriteByte(Id);
}
}
Скорее всего, Id как-то связан с классом, так что он может быть константой.
Проверил CRTP by VladD:
using System;
static class Programm {
public abstract class Packet<TSelf> where TSelf : Packet<TSelf> {
public static byte Id;
public void Write() { Console.WriteLine(Id); }
}
public class Ipv4Packet : Packet<Ipv4Packet> {
static Ipv4Packet() { Id = 1; }
}
public class Ipv6Packet : Packet<Ipv6Packet> {
static Ipv6Packet() { Id = 2; }
}
static void Main() {
var a1 = new Ipv4Packet(); a1.Write();
var a2 = new Ipv6Packet(); a2.Write();
a1.Write();
a2.Write();
}
}
-->
1
2
1
2
Можно взять на вооружение!
Например, можно применить CRTP:
public abstract class Packet<TSelf> where TSelf : Packet<TSelf>
{
public static byte Id;
public virtual void Write(ref RawPacket packet)
{
packet.WriteByte(Id);
}
}
Использовать нужно так:
public class Ipv4Packet : Packet<Ipv4Packet>
{
// ...
}
Заметьте, что с CRTP различные пакеты не имеют общего предка, так что если он реально нужен, вам понадобится унаследовать Packet<TSelf> от нешаблонного Packet:
public abstract class Packet
{
// общая функциональность тут, возможно как abstract
}
public abstract class Packet<TSelf> : Packet where TSelf : Packet<TSelf>
{
// ...