C
C#8mo ago
Tim

✅ Enum and generics

Hello there! In our current code, we use structs to represent a packet; Packet<Data>. This packet (struct) has a ushort Identifier and a Codec<Data> Codec. This Identifier should be unique, but currently we assign these manually:
Packet<String> SendMessage = new Packet<String>(0, CodecString.UTF8);
Packet<String> SendMessage = new Packet<String>(0, CodecString.UTF8);
This isn't ideal, so I considered using an Enum to represent the packet Id's, however that would mean that the packets would be in 2 places, the enum and the Packet instance holding the codec. Is there a way to combine this? The ideal solution would be an enum with generic <Data> to allow enforcing the codec used:
public void SendPacket<Data>(PacketEnum<Data> enumType, Data data){}
public void SendPacket<Data>(PacketEnum<Data> enumType, Data data){}
But that is obviously not supported.
19 Replies
Tim
Tim8mo ago
So I'm either looking for - A way to enforce unique Identifiers (incrementing) - A way to use an enum while enforcing a generic type
reflectronic
reflectronic8mo ago
what you want is a discriminated union as you can see, right now it takes a lot of manual work to get something like that
reflectronic
reflectronic8mo ago
adding a way to express such things more naturally in C# is a hot design issue that the language team is investigating https://github.com/dotnet/csharplang/discussions/7010
GitHub
[LDM] - Union Types · dotnet csharplang · Discussion #7010
The following is a summary of discussions held on discriminated unions in C# by members of the C# language design team. It is not a proposal, and it is not the actual meeting notes. Union Types Uni...
Tim
Tim8mo ago
Ah, interesting The tag union is probably the closest to what I want Well, I guess I'll just use the enum + instance method for now
jcotton42
jcotton428mo ago
@Tim the libraries dotVariant or OneOf can do this for you
Erroneous Fatality
You can just use a Guid for your identifier. It should be globally unique on generation; no need to do discriminations in the database. Could you elaborate on your usecase of using an enum in a generic type? It's possible but I'm not sure what you're trying to achieve.
jcotton42
jcotton428mo ago
Now the packet has 112 extra bits for no reason An enum is a good choice here
Erroneous Fatality
I mean, it's a tradeoff 😄 Could you explain where the enum is used and how? I'm not understanding it from the text so far. @jcotton42
Tim
Tim8mo ago
No enum right now Defining packet Id's manually, given to the Packet struct instances An enum works But it will duplicate with the Packet struct e.g.
Erroneous Fatality
I don't see any advantage to using an enum in this scenario You just want a unique Id, inside the ushort scope?
Tim
Tim8mo ago
Packet<String> SendMessage = new Packet<String>(...);

enum PacketIds{
SEND_MESSAGE
}
Packet<String> SendMessage = new Packet<String>(...);

enum PacketIds{
SEND_MESSAGE
}
basically yes
Erroneous Fatality
shouldn't all send message instances have a different Id?
Tim
Tim8mo ago
they should
Erroneous Fatality
if you use that enum, they'll all have the same value.
Tim
Tim8mo ago
1 enum entry per packet so incrementing Id
Erroneous Fatality
enum is not a good choice here. Enums represent a collection of bussiness-sensible labeled values
Tim
Tim8mo ago
Yes- packet type Id's
Erroneous Fatality
Ok, so lets say you have this enum:
enum PacketIds{
SEND_MESSAGE
}
enum PacketIds{
SEND_MESSAGE
}
you make one packet, which uses PacketIds.SEND_MESSAGE value which value will the next packet use for its Id? an enum does not generate values. It's simply a dictionary/map between labels and values: By default, this
enum PacketIds{
SEND_MESSAGE
}
enum PacketIds{
SEND_MESSAGE
}
is actually
enum PacketIds : int{
SEND_MESSAGE = 0
}
enum PacketIds : int{
SEND_MESSAGE = 0
}
Whenever you use PacketIds.SEND_MESSAGE, you're just using 0
Tim
Tim8mo ago
Yeah ofc . I got that I don't want 'generating' enums that'd be useless since it's mostly a compile time thing It's solved tho. Seems C# doesn't solve it itself, so I can choose between - using an enum and having repeating packet names (enum entry SEND_MESSAGE and packet instance SendMessage etc etc.) - manually assigning Identifiers - using a library (bit over the top for me tho) It just seemed logical to make use of the enum property that it creates unique incrementing Id's But the redundancy that creates in my case made me look for another alternative