提问人:MP9 提问时间:5/16/2023 最后编辑:Guru StronMP9 更新时间:5/16/2023 访问量:861
C# 模板函数:不能在“T”中执行非虚拟成员查找,因为它是一个类型参数
C# Template Function: Cannot do non-virutal member lookup in 'T' because it is a type parameter
问:
我有一个系统,其中每个接口/类都有两个代码 (, ) - 这是为了有效地从十六进制字符串保存和重新生成对象。InterfaceCode
SubtypeCode
我现在有一个特定的用例,我需要一个继承 .
为了检查 ItemCode 是否与所需的接口/类匹配,我想将值与 和 进行比较(见下文)。可悲的是,这不起作用,因为我无法访问类型参数 () 的成员。Iitem
T.InterfaceCode
T.SubtypeCode
CS0704
public static T AsType<T>(string ItemCode) where T : Iitem
{
if (ItemCode.Length < 5) return null;
ItemCodeDes itemCode = new ItemCodeDes(ItemCode);
if(itemCode.InterfaceCode != T.InterfaceCode) return null; //Error CS0704 Cannot do non-virtual member lookup in 'T' because it is a type parameter
if(itemCode.SubtypeCode != T.SubtypeCode) return null; //same here...
//...
}
跟
public static ushort SubtypeCode { get; } = 0;
public static ushort InterfaceCode { get; } = 0;
我真的不会为每个类硬编码查找表(大约有 100-200 个)。
有没有一个好的干净的解决方案来解决我的问题(不使用反射)?
编辑:我仍在使用 C# .NET Core 3.1
对于那些需要更多背景信息的人:
public class Iitem
{
public static ushort SubtypeCode { get; } = 0;
public static ushort InterfaceCode { get; } = 0;
public Iitem(string itemName, string description, ItemTier tier, ushort id)
{
Name = itemName;
Tier = tier;
Description = description;
Id = id;
}
public string Name { get; }
public string Description { get; }
public ItemTier Tier { get; }
public ushort Id { get; }
/// <summary>
/// Gibt den itemspezifischen Code zurück.
/// </summary>
/// <returns>Itemcode als Hex-String</returns>
public virtual string GetItemCode()
{
return GenerateItemCode(0, 0);
}
internal string GenerateItemCode(ushort Interface, ushort Subtype, ulong Generationspecifics = 0)
{
return Interface.ToString("X1") + Subtype.ToString("X1") + Id.ToString("X3") + (Generationspecifics != 0 ? Generationspecifics.ToString("X") : "");
}
/// <summary>
/// Generiert einen String mit den Stats und einer Beschreibung des Items.
/// </summary>
/// <returns></returns>
public virtual string PrintItem()
{
return Name + " (" + Tier.ToString() + ") - " + Description;
}
public enum ItemTier
{
Common,
Uncommon,
Epic,
Legendary,
Heavengrade,
Forbidden,
}
}
private class ItemCodeDes
{
public ItemCodeDes(string ItemCode)
{
if (ItemCode.Length < 5) return;
InterfaceCode = ushort.Parse(ItemCode[0].ToString(), System.Globalization.NumberStyles.HexNumber);
SubtypeCode = ushort.Parse(ItemCode[1].ToString(), System.Globalization.NumberStyles.HexNumber);
ItemId = ushort.Parse(ItemCode.Substring(2, 3), System.Globalization.NumberStyles.HexNumber);
if (ItemCode.Length > 5)
Generationspecifics = ItemCode.Substring(5);
}
public ushort InterfaceCode { get; }
public ushort SubtypeCode { get; }
public ushort ItemId { get; }
public string Generationspecifics { get; } = "";
}
答:
2赞
Guru Stron
5/16/2023
#1
有没有一个好的干净的解决方案来解决我的问题(不使用反射)?
有,但它需要您迁移到最新的语言版本。这将启用在接口中使用静态抽象成员的选项。引入相应的接口,然后使用它:
public interface IIitem // probably you will need to use better name
{
public static abstract ushort SubtypeCode { get; }
public static abstract ushort InterfaceCode { get; }
}
public class Iitem : IIitem
{
// ...
}
并约束泛型参数:
public static T AsType<T>(string ItemCode) where T : Iitem, IIitem
{
// ...
}
如果您无法升级以支持新的语言版本,那么您将需要使用反射或重构该方法(如果我正确理解这种情况 - 我通常在类似情况下使用类型的属性,并构建从类型到代码的静态字典映射,反之亦然,因此“缓存”反射)。
评论
0赞
Fildor
5/16/2023
我觉得如果你选择使用(运行时/动态,而不仅仅是一次性启动)反射,你可以吻“这是为了有效地从十六进制字符串中保存和重新生成对象”再见。
0赞
Guru Stron
5/16/2023
@Fildor,您可以“缓存”反射。例如这里。或者在这种情况下,静态字典可能会起作用(需要查看更多代码)。
1赞
Fildor
5/16/2023
至少,你需要做一些“魔术”。这就是我的意思。我想,幼稚的反思不会削减它。
1赞
MP9
5/16/2023
我升级到最新的语言版本,并按照您的建议实现了界面。谢谢!
0赞
Guru Stron
5/17/2023
@MP9很高兴它有所帮助!小 P.S. - C# 泛型不是模板(如果您来自 C++ 背景 - 请查看此文档)
评论
Iitem
static abstract
Iitem
Iitem