可重写的方法不能是静态的:我还能怎样做我想做的事情?

2023-12-29

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

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 方法设为公共,因为显然泛型类不能具有受保护或受保护内部成员。必须公开这一点并不理想,但也不至于破坏交易。

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

这个版本甚至无法构建。

有什么方法可以做我想做的事情并仍然保持我的班级静态吗?我真的很想避免每次调用 Types ToString.Get() 时都必须实例化 Type ToString 对象。


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

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 method.


EDIT:解释评论中的附加信息。

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

[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 and Foo.Baz

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可重写的方法不能是静态的:我还能怎样做我想做的事情? 的相关文章

随机推荐

  • 使用 ggplot2 将每个第 N 轴标签加粗

    是否可以使用 ggplot2 将轴上的第 N 个刻度设为粗体 我只想将轴标记为粗体 小线 而不是文本 在绘图中显示每日数据时 这对于突出显示每 7 个刻度非常有用 我想保留每一天的刻度线 我无法找到有关此主题的任何内容 任何帮助将不胜感激
  • Python:将数据类型从整数更改为浮点时出现内存错误

    我有一个大小为 13000 300000 的数组 其中填充了从 0 到 255 的整数 我想将它们的数据类型从整数更改为浮点 就好像数据是 numpy 数组一样 data astype float 当将其数据类型从整数更改为浮点时 它显示内
  • Git 终端使用旧帐户将文件推送到我的新 github 帐户[重复]

    这个问题在这里已经有答案了 我最近创建了一个新的 github 帐户 当我尝试通过 git 终端将一些文件推送到我的新帐户的存储库中时 它告诉我无权访问新帐户 因此 我手动删除了之前帐户的旧凭据 并通过 git 终端保存了新凭据 现在 它将
  • ASP.NET MVC 子字符串帮助

    我有一个 ASP NET MVC 应用程序 用于显示新闻文章 对于主要段落 我有一个截断和 HTML 标签剥离器 例如 p p 这两个函数来自扩展 如下所示 public static string RemoveHTMLTags this
  • rsync 在传输过程中突然无限期挂起

    在过去的几年里 我一直在使用 rsync 单行程序将 Mac Mini 桌面 OSX 10 9 2 5 GHz i5 4 GB RAM 上的重要文件夹备份到 FreeNAS 盒子 0 7 2 Sabanda 修订版 5266 Pentium
  • 获取缩放散点图中的面积或元素

    我有以下问题 我想放大散点图 然后选择所有显示的元素 以某种方式获得放大散点图中的显示区域就足够了 从该区域的范围我可以确定哪些元素显示在该区域中 哪些不显示 edit 找到解决方案 实现 AxisChangeListener 接口 imp
  • Pandas:如何将系列的多重索引折叠为日期时间索引?

    作为后续Pandas groupby 按学期分组 https stackoverflow com questions 51854809 pandas groupby group by semester我需要将系列的多重索引折叠为日期时间索引
  • 如何在 ASP.Net MVC for Mono 中使用异步

    我正在使用 Visual Studio 2017 for Mac 在 Mono 中创建 ASP Net MVC 项目 我添加了基本的控制器 视图 模型等 并且运行良好 但是 一旦使 Index 方法异步 我就会收到以下错误 System I
  • 如何根据第三个变量对分散标记进行着色

    我想制作一个散点图 使用 matplotlib 其中点根据第三个变量进行着色 我已经非常接近这个了 plt scatter w M c p marker s 其中 w 和 M 是数据点 p 是我想要着色的变量 不过我想用灰度而不是彩色来做
  • Flutter Provider - 重建列表项而不是列表视图

    我正在使用 Provider 包来管理我的应用程序业务逻辑 但我遇到了一个问题 即正在重建整个 ListView 而不是单个 ListTile 下面的 UI 可让您更好地理解 目前 如果我滚动到列表底部 点击最后一项的复选框 我看不到复选框
  • SetHidden 不起作用[重复]

    这个问题在这里已经有答案了 我正在 cocoa 中开发一个应用程序 我需要隐藏放置在 NSView 中的进度条 并在那个地方显示一个 NSTextfield 我使用了以下代码 进度条设置隐藏 TRUE 文本字段设置隐藏 FALSE 但这个代
  • WebGL 上出现错误“Tex 图像 TEXTURE_2D level 0 正在引发延迟初始化”

    我收到错误消息 Error WebGL warning drawElements Tex image TEXTURE 2D level 0 is incurring lazy initialization 在 WebGL 上 我想知道它的实
  • 如何从 SPSS 中的另一个语法文件获取语法文件?

    在 R 中有source函数 您可以从另一个 R 脚本获取 R 脚本 我希望能够在 SPSS 中做同样的事情 如何从另一个 SPSS 语法文件获取 SPSS 语法文件 根据 AndyW 的评论进行了更新 有的是INSERT and INCL
  • 覆盖 pytest 参数化函数名称

    我的参数决定了参数化 pytest 的名称 我将使用一些随机参数进行这些测试 为了使 junit 中的报告名称不会混乱 我想为每个参数化测试创建一个静态名称 是否可以 JUnit似乎有一个参数 更改参数化测试的名称 https stacko
  • 使用什么(纯)Python 库进行 AES 256 加密? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 最好是纯的 python 库来进行 AES 256 加密和解密 该库应支持 CBC 密码模式并使用 PKCS7 填充根据我
  • 如何在 VSIX 包安装上注册键绑定代码

    我只想在安装期间向 Visual Studio 包添加一次键盘快捷键 基本上我知道如何从包代码中做到这一点 例如 var dte GetGlobalService typeof DTE as DTE2 if dte null dte Com
  • 是否可以将多个验证组分配给单个验证控件?

    我有一个这样的表格 UserID has to be validated when user clicks Check Availability and Submit 因此 必须为 UserID 必需的字段验证器分配两个组 好像现在只分配了
  • 组件更新时重置 Snackbar 上的 autoHideDuration 计时器

    我希望只有当组件未更新时 小吃栏才会在 2 秒内超时 如果它更新了 我希望计时器在还没有达到 2 秒时重置 useEffect gt setOpen true props single message return div props si
  • 在哪里可以找到 DockerCli.exe

    我正在尝试将 Docker 切换到我的 Windows Server Core 1903 计算机 无桌面 上的 Windows 容器 This https forums docker com t cli to switch between
  • 可重写的方法不能是静态的:我还能怎样做我想做的事情?

    我有一系列静态类 用于获取枚举值的字符串 它们看起来都是这样的 public static class MyEnumToString private static Dictionary