Extending Variant classes in C#

Godot Version

4.2.stable.mono

Question

Hey guys, quick question. In C#, is it possible for a class to extend a variant type? Such as Dictionary. I’m attempting this but get a GD0301: The generic type argument must be a Variant compatible type error when using it as a variant arg.

Calling code…

...
//    Error occurs on second generic
public Dictionary<long, PlayerInfo> Players { get; private set; } = new();
...

And the class in question…

public partial class PlayerInfo : Dictionary<string, Variant> {
    public long Id {
        get => this["Id"].AsInt64();
        set => this["Id"] = value;
    }
    public string Name {
        get => this["Name"].AsString();
        set => this["Name"] = value;
    }
}

By using the Dictionary in the System.Collections.Generic namespace instead of the Godot.Collections namespace, you would be able to create the dictionary of type Dictionary<long, PlayerInfo>. It is generally recommended to use C# builtin collections instead of Godot ones, unless you are trying to export them to the inspector. See C# collections — Godot Engine (stable) documentation in English for more.

Thanks for the reply, I guess I should elaborate on what it is I’m trying to achieve.

I would like to create a class that I can pass through to an Rpc using the Godot multiplayer API. Calling Rpc or RpcId requires that you pass args of type Variant.

This is simple enough with GDScript, but with C# it creates an uncomfortable situation where you are forced to use a Dictionary, even when you have a strongly defined data structure.

To get around this I am trying to extend the supported Variant Dictionary type with accessor methods for the known data fields, but clearly, the engine doesn’t like that.

Although you would be able to inherit Godot.Collections.Dictionary, and your method would actually work, I do not recommend extending basic data structures provided by Godot in such a way. The main reason is that there would be other unwanted properties and methods within your PlayerInfo class other that your Id and Name properties, for example other developers could call PlayerInfo.Remove("Id") and not calling Id would result in an exception.

You can use the Godot dictionary as is. There are examples in Godot where they would use it for plain information holders, such as raycast. To enable fast lookup, your Players property then becomes:

public Dictionary<long, Dictionary<string, Variant>> Players { get; private set; } = new();