【问题标题】:How can I make a strongly typed set of string values? [duplicate]如何制作一组强类型的字符串值? [复制]
【发布时间】:2021-10-18 17:03:09
【问题描述】:

我知道枚举不能是字符串

我想要一个具有enum 实用程序的数据结构,但它返回字符串而不是整数。需要明确的是,我希望返回类型是类枚举类型,而不是string。基本上,我希望能够强制属性可用作字符串,但只允许设置为已定义字符串集中的值。类似的东西

stringenum Unit {
    Pixels = "px",
    Inches = "in"
}

class Settings {
    public Unit Unit { get; set; }
}

var settings = new Settings() { Unit = Unit.Pixels };

...

unitLabel.Text = settings.Unit;

我见过一些解决方案,它们只是创建一个具有返回特定字符串的属性的类。但是,我需要将返回类型限制为一个集合,而不仅仅是任何字符串。

编辑澄清

除了这个方法之外,考虑我之前的例子:

public void WriteUnit(Unit unit)
{
    Console.WriteLine(unit);
}

// Calling
WriteUnit(Unit.Pixels); // Prints "px"
WriteUnit("px"); // ARGUMENT EXCEPTION

如果你传递一个字符串,这个方法会抛出一个ArgumentException。它只接受类型。这正是我正在寻找的。​​p>

【问题讨论】:

  • 确实@Fildor,也许DescriptionAttribute可以匹配问题,有点粗鲁。
  • 看看这个答案:stackoverflow.com/a/2650090/982149
  • 为什么不使用枚举成员名(如果需要字符串,则使用 ToString()),而其余时间将其用作枚举? enum Unit { px, [in] }var x = Unit.px; string xs = x.ToString() - 通常您只需要一个用于输出目的的字符串...
  • 无论何时你想要字符串,但请记住,你经常可以使用调用 toString 的东西——例如,如果你使用 Console.WriteLine 来调用它,它会调用 ToString.. 如果你用字符串插值它也会。您可能可以将代码中的“在枚举上调用 tostring 的位置数”简化为一两个...
  • 你可以使用打字机然后...class Unit{ public Unit Pixel { get => return PixelUnit } }class PixelUnit:Unit { public override string ToString() => "px"; }}?应该在您的 WriteUnit 中工作,Console.WriteLine 将调用 ToString().. 如果您需要,单元可以有一个字符串解析例程.. ?如果您真的希望在传递字符串时发生爆炸,可以添加会爆炸的 WriteUnit 重载.. 但是添加重载只是为了让开发人员看到“不要用字符串调用此方法”绝对是奇怪的.. 更容易根本不提供方法,我认为

标签: c# set


【解决方案1】:

如 cmets 中所述,您不能直接将枚举映射到字符串。

也就是说,没有什么可以阻止您创建枚举到字符串值的映射,该映射只能通过枚举访问。如果您维护映射,则可以保证该值始终存在。

public enum Unit
{
    Pixels,
    Inches
}

public static class UnitMapper
{
    private static readonly Dictionary<Unit, string> _map
        = new Dictionary<UserQuery.Unit, string>()
        {
            { Unit.Pixels, "px" },
            { Unit.Inches, "in" }
        }
        
    public static string GetUnit(Unit unit)
    {
        return _map[unit];
    }
}

根据您的其他 cmets,这可以与自定义的用户定义的隐式运算符结合使用,为您提供您正在寻找的功能类型,尽管您仍然必须调用覆盖的 .ToString() 来输出字符串。

public struct UnitWrapper
{
    private readonly string _unitString;
    private readonly Unit _unit;
    
    public UnitWrapper(Unit unit)
    {
        _unit = unit;
        _unitString = UnitMapper.GetUnit(_unit);
    }

    public static implicit operator UnitWrapper(Unit unit)
    {
        return new UnitWrapper(unit);
    }
    

    public override string ToString() => _unitString;
}

然后可以按如下方式使用:

public class Settings
{
    public UnitWrapper UnitWrapper { get; set; }
}
var settings = new Settings { UnitWrapper = Unit.Pixels };
string px = settings.UnitWrapper.ToString();

【讨论】:

  • 谢谢,大卫。我需要解决的核心问题是我想将属性限制为只允许某些字符串值的类型。这确实允许我使用方法从集合中获取字符串,但不能定义具有限制允许字符串集合的类型的属性。
  • 我不确定我是否遵循。如果您覆盖属性的设置器以扩展此用例,您始终可以准确限制任何特定属性的允许范围。
  • 因此,根据您的回答,我无法为类提供类型为 Unit 的属性,该属性的计算结果为字符串。我必须调用一个方法来获取基于 Unit 值的字符串。我本质上是在问,我如何创建一个表现得好像枚举可以返回字符串而不是整数的类型。
  • @Fildor 仅利用字符串格式覆盖。您可以使用Console.WriteLine($"{unit}"); 轻松完成同样的事情。在任何一种情况下,它都会完全混淆意图。我同意,这是一个可怕的黑客:)。至少在显式调用.ToString() 时,您想要做什么是显而易见的。这是一个很好的简化,它避免了任何类型的外部映射
  • @DavidL 我发现自己“追逐我的尾巴”想要将所有要求压缩成一种类型......我真的认为这也不值得麻烦。这让客户感到惊讶。
猜你喜欢
  • 2019-07-06
  • 2020-02-28
  • 1970-01-01
  • 2011-10-06
  • 2015-10-21
  • 2020-09-17
  • 1970-01-01
  • 2017-08-25
相关资源
最近更新 更多