C# 可重写的方法不能是静态的:除此之外,我还能做什么';我想做什么?

C# 可重写的方法不能是静态的:除此之外,我还能做什么';我想做什么?,c#,C#,我有一系列静态类,用于获取枚举值的字符串。它们看起来都是这样的: public static class MyEnumToString { private static Dictionary<MyEnum, string> map = new Dictionary<MyEnum, string>(); public static string Get(MyEnum type) { PopulateEmptyMap(); return m

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

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";
  }
}
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";
  }
}
public enum Foo
{
    [Description("Hello")]
    Bar,

    [Description("World")]
    Baz
}

var value = Foo.Bar;
var description = value.GetDescription(); // Hello
公共静态类MyEnumToString
{
私有静态字典映射
=新字典();
公共静态字符串Get(MyEnum类型)
{
PopulateEmptyMap();
返回映射[类型];
}
静态void PopulateEmptyMap()
{
如果(!map.Any())
{
PopulateMap();
}
}
私有静态void PopulateMap()
{
map[MyEnum.enum1]=“枚举1的字符串”;
map[MyEnum.enum2]=“枚举2的字符串”;
}
}
我有多个这样的类,它们使用的枚举类型和字符串值不同。显然,我应该组合这些类以减少重复代码

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

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";
  }
}
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";
  }
}
public enum Foo
{
    [Description("Hello")]
    Bar,

    [Description("World")]
    Baz
}

var value = Foo.Bar;
var description = value.GetDescription(); // Hello
公共静态类TypeToString
{
公共静态字典映射
=新字典();
公共静态字符串Get(TType类型)
{
PopulateEmptyMap();
返回映射[类型];
}
静态void PopulateEmptyMap()
{
如果(!map.Any())
{
PopulateMap();
}
}
公共抽象静态void PopulateMap();
}
公共静态类MyEnumToString:TypeToString
{
公共静态void PopulateMap()
{
map[MyEnum.enum1]=“枚举1的字符串”;
map[MyEnum.enum2]=“枚举2的字符串”;
}
}
我必须公开字典和PopulateMap方法,因为显然泛型类不能有受保护的或受保护的内部成员。必须公开这一点并不理想,但也不是交易的破坏者

我最担心的是“可重写的方法不能是静态的”,所以我的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();
    }
}
根据需要,如果反射对您来说太慢,您可以缓存描述,只需修改
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)];
        }
    }
}
公共静态类枚举扩展
{
私有静态只读ConcurrentDictionary缓存=新建ConcurrentDictionary();
公共静态字符串GetDescription(此枚举值、字符串键)
{
var enumType=value.GetType();
var cache=Caches.GetOrAdd(enumType,type=>newdescriptioncache(type));
返回cache.GetDescription(值、键);
}
公共静态IEnumerable GetValuesFromDescription(字符串键,字符串描述)
其中TEnum:struct
{
var cache=Caches.GetOrAdd(typeof(TEnum),type=>newdescriptioncache(type));
返回cache.GetValues(key,description)。选择(value=>(TEnum)(object)value);
}
私有类描述缓存
{
私有只读ILookup\u项;
私有只读ILookup\u反向;
公共描述缓存(类型enumType)
{
如果(!enumType.IsEnum)
抛出新ArgumentException(“非枚举”);
_items=(来自Enum.GetValues(enumType.Cast()中的值)
let field=enumType.GetField(value.ToString())
where字段!=null
来自字段中的属性。GetCustomAttributes(typeof(DescriptionEntryAttribute),false)。of type()
选择新{value,key=attribute.key,description=attribute.value})
.ToLookup(i=>i.value,i=>Tuple.Create(i.key,i.description));
_反向=(来自grp中的_项)
从grp中的描述
选择新{value=grp.Key,description})
.ToLookup(i=>i.description,i=>i.value);
}
公共字符串GetDescription(枚举值、字符串键)
{
var tuple=_items[value].FirstOrDefault(i=>i.Item1==key);
返回元组!=null?tuple.Item2:null;
}
公共IEnumerable GetValues(字符串键、字符串描述)
{
return_reverse[Tuple.Create(key,description)];
}
}
}
这样:

  • Foo.Bar.GetDescription(“Name”)
    返回
    “Hello”
  • EnumExtensions.GetValuesFromDescription(“Title”、“Some Title”)
    返回包含
    Foo.Bar
    Foo.Baz

这应该足以让你开始,现在你应该调整它,以满足你的需要。例如,您可以使用枚举而不是字符串作为键,这将有助于避免键入错误,但我不知道这是否适合您的需要。

您的问题是静态方法和变量本质上不是继承的。它们是变量,不作用于类本身的实例,但为类提供一些功能

所以你有一堆不同的枚举,你想根据不同的东西填充它们。让我们看看你有哪些部分,哪些是共同的:

  • PopulateMap:不常见
  • 枚举类型:不常见
  • 存储变量:公共
  • 填充映射(如果为空):通用
所以,你真正想要的是一种方法