gpt4 book ai didi

c# - 可覆盖的方法不能是静态的 : How else can I do what I'm trying to do?

转载 作者:行者123 更新时间:2023-11-30 12:27:25 25 4
gpt4 key购买 nike

我有一系列静态类,用于获取枚举值的字符串。它们看起来都像这样:

public static class MyEnumToString
{
private static Dictionary<MyEnum, string> map
= new Dictionary<MyEnum, string>();

public static string Get(MyEnum type)
{
PopulateEmptyMap();
return map[type];
}

static void PopulateEmptyMap()
{
if (!map.Any())
{
PopulateMap();
}
}

private static void PopulateMap()
{
map[MyEnum.enum1] = "string for enum 1";
map[MyEnum.enum2] = "string for enum 2";
}
}

我有多个这样的类,它们使用的枚举类型和字符串值不同。显然,我应该合并这些类以减少重复代码。

我尝试做的是创建通用基类,以便它可以处理任何类型,然后为继承的类实现 PopulateMap。如果可能的话,它看起来像这样:

public static class TypeToString<TType>
{
public static Dictionary<TType, string> map
= new Dictionary<TType, string>();

public static string Get(TType type)
{
PopulateEmptyMap();
return map[type];
}

static void PopulateEmptyMap()
{
if (!map.Any())
{
PopulateMap();
}
}

public abstract static void PopulateMap();
}

public static class MyEnumToString: TypeToString<MyEnum>
{
public static void PopulateMap()
{
map[MyEnum.enum1] = "string for enum 1";
map[MyEnum.enum2] = "string for enum 2";
}
}

我必须公开 Dictionary 和 PopulateMap 方法,因为显然泛型类不能有 protected 或 protected 内部成员。必须公开这一点并不理想,但不会破坏交易。

我被挂断的是“可重写的方法不能是静态的”这一事实,因此我的 PopulateMap 方法不能既是抽象的又是静态的。如果它不是静态的,就不能从其他静态方法中调用它。如果它不是抽象的,则不会调用继承类的 PopulateMap。

这个版本甚至没有构建。

有什么方法可以做我正在尝试做的事情并且仍然保持我的类静态?我真的很想避免每次调用 TypeToString.Get() 时都必须有一个实例化的 TypeToString 对象。

最佳答案

这是一个方便的扩展方法,因为我猜您正在尝试将一些描述文本映射到枚举值:

public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
if (field == null)
return value.ToString();

var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false)
.OfType<DescriptionAttribute>()
.SingleOrDefault();

return attribute != null
? attribute.Description
: value.ToString();
}
}

像这样使用它:

public enum Foo
{
[Description("Hello")]
Bar,

[Description("World")]
Baz
}

var value = Foo.Bar;
var description = value.GetDescription(); // Hello

根据您的需要,如果反射对您来说太慢,您可以缓存描述,只需修改 GetDescription方法。


编辑:考虑评论中的附加信息。

因为看起来您需要更可扩展的东西,您可以使用自定义属性:

[AttributeUsage(AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
public sealed class DescriptionEntryAttribute : Attribute
{
public string Key { get; private set; }
public string Value { get; private set; }

public DescriptionEntryAttribute(string key, string value)
{
Key = key;
Value = value;
}
}

哪个会让你这样做:

public enum Foo
{
[DescriptionEntry("Name", "Hello")]
[DescriptionEntry("Title", "Some title")]
Bar,

[DescriptionEntry("Name", "World")]
[DescriptionEntry("Title", "Some title")]
Baz
}

现在,要阅读这个东西,我建议你将它存储在这样的缓存中:

public static class EnumExtensions
{
private static readonly ConcurrentDictionary<Type, DescriptionCache> Caches = new ConcurrentDictionary<Type, DescriptionCache>();

public static string GetDescription(this Enum value, string key)
{
var enumType = value.GetType();
var cache = Caches.GetOrAdd(enumType, type => new DescriptionCache(type));
return cache.GetDescription(value, key);
}

public static IEnumerable<TEnum> GetValuesFromDescription<TEnum>(string key, string description)
where TEnum : struct
{
var cache = Caches.GetOrAdd(typeof(TEnum), type => new DescriptionCache(type));
return cache.GetValues(key, description).Select(value => (TEnum)(object)value);
}

private class DescriptionCache
{
private readonly ILookup<Enum, Tuple<string, string>> _items;
private readonly ILookup<Tuple<string, string>, Enum> _reverse;

public DescriptionCache(Type enumType)
{
if (!enumType.IsEnum)
throw new ArgumentException("Not an enum");

_items = (from value in Enum.GetValues(enumType).Cast<Enum>()
let field = enumType.GetField(value.ToString())
where field != null
from attribute in field.GetCustomAttributes(typeof (DescriptionEntryAttribute), false).OfType<DescriptionEntryAttribute>()
select new {value, key = attribute.Key, description = attribute.Value})
.ToLookup(i => i.value, i => Tuple.Create(i.key, i.description));

_reverse = (from grp in _items
from description in grp
select new {value = grp.Key, description})
.ToLookup(i => i.description, i => i.value);
}

public string GetDescription(Enum value, string key)
{
var tuple = _items[value].FirstOrDefault(i => i.Item1 == key);
return tuple != null ? tuple.Item2 : null;
}

public IEnumerable<Enum> GetValues(string key, string description)
{
return _reverse[Tuple.Create(key, description)];
}
}
}

这样:

  • Foo.Bar.GetDescription("Name")返回 "Hello"
  • EnumExtensions.GetValuesFromDescription<Foo>("Title", "Some title")返回包含 Foo.Bar 的序列和 Foo.Baz

这应该足以让您入门,现在您应该根据自己的需要对其进行调整。例如,您可以使用枚举而不是字符串作为键,这有助于避免输入错误,但我不知道这是否适合您的需要。

关于c# - 可覆盖的方法不能是静态的 : How else can I do what I'm trying to do?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25490269/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com