I'm trying to make it to where I can't access the record properties based on their name but rather though an extension method.
For instance, I want to be able to do this
Axe.GetById(1378).GetName()
But not be able to do
Axe.GetById(1378).Name
I tried declaring a private field inside the record, but then I can't access it in my extension method at all in order to return it.
public sealed record AxeEnum(string Name, int LevelReq, int ItemId)
{
private int privateField;
}
static class Axe
{
static Dictionary<int, AxeEnum> AXES = new Dictionary<int, AxeEnum>();
static AxeEnum STEEL = new AxeEnum("Steel", 41, 1378);
static Axe()
{
AXES.Add(GetId(STEEL), STEEL);
}
public static AxeEnum GetById(int id)
{
AXES.TryGetValue(id, out var axe);
return axe;
}
public static int GetLvlReq(this AxeEnum axe) => axe.LevelReq;
public static int GetId(this AxeEnum axe) => axe.ItemId;
public static string GetName(this AxeEnum axe) => axe.Name;
}
CodePudding user response:
where I can't access the record properties based on their name
If you don't want the shape that records present: don't use records; just create your own class
with whatever members and accessibility rules you want.
I tried declaring a private field inside the record, but then I can't access it in my extension method at all in order to return it.
Extension methods must still respect accessibility rules; at the moment the field is private
, which is inaccessible except by code in that type, or nested types, and extension methods must be on top-level (non-nested) types. We can't make use of protected
, since extension methods must be on static
types (which can't inherit anything), plus the record
here is sealed
. So: that leaves internal
:
public sealed record AxeEnum(string Name, int LevelReq, int ItemId)
{
internal int privateField;
}
Personally, though: I'd probably just make this a public instance property or method on the record itself.
CodePudding user response:
It's sort-of possible to do this if you make AxeEnum
a class instead of a record and declare it nested inside the Axe
class.
You also have to make a private nested interface for the properties you want to access from within the class.
It would look something like this:
static class Axe
{
// Private interface for the properties that this class needs to access.
interface IAxeEnumPrivates
{
string Name { get; }
int LevelReq { get; }
int ItemId { get; }
}
// Nested class with explicit implementation of the properties.
public sealed class AxeEnum : IAxeEnumPrivates
{
public AxeEnum(string name, int levelReq, int itemId)
{
_name = name;
_levelReq = levelReq;
_itemId = itemId;
}
string IAxeEnumPrivates.Name => _name;
int IAxeEnumPrivates.LevelReq => _levelReq;
int IAxeEnumPrivates.ItemId => _itemId;
readonly string _name;
readonly int _levelReq;
readonly int _itemId;
}
static Dictionary<int, AxeEnum> AXES = new Dictionary<int, AxeEnum>();
static AxeEnum STEEL = new AxeEnum("Steel", 41, 1378);
static Axe()
{
AXES.Add(GetId(STEEL), STEEL);
}
public static AxeEnum? GetById(int id)
{
AXES.TryGetValue(id, out var axe);
return axe;
}
public static void DoSomethingWithAxe(AxeEnum axe)
{
// Need to assign the concrete class to a variable of the interface type in order
// to access its properties.
IAxeEnumPrivates iAxe = axe;
// Now you can do things with the properties:
Console.WriteLine(iAxe.Name);
Console.WriteLine(iAxe.LevelReq);
Console.WriteLine(iAxe.ItemId);
// But you can't access the properties via the concrete class:
// Console.WriteLine(axe.Name); // Won't compile!
}
// We must implement these by casting the concrete AxeEnum class
// to the private interface, so that we can access the properties.
// This is completely safe because AxeEnum implements the interface.
public static int GetLvlReq(this AxeEnum axe) => ((IAxeEnumPrivates)axe).LevelReq;
public static int GetId(this AxeEnum axe) => ((IAxeEnumPrivates)axe).ItemId;
public static string GetName(this AxeEnum axe) => ((IAxeEnumPrivates)axe).Name;
}
However this looks like a fiddly solution to an X-Y problem...