【问题标题】:How to force a method parameter to be one from a specific parameter class?如何强制方法参数来自特定参数类?
【发布时间】:2018-07-12 08:45:29
【问题描述】:

首先让我试着解释一下我的情况。

由于我们无法将字符串值添加到枚举中,并且 我没有添加自定义参数类来存储和读取它(出于性能原因,因为如果我使用类似的东西会涉及反射:public class StringValueAttribute : Attribute),所以我决定使用以下类型的类:

public class Permissions
{
    public const string X1 = "X1";
    public const string X2 = "X2";
    public const string X3 = "X3";
    ....
    public const string X43 = "CAN_HAVE A LONG NAME AND NOT FOLLOWING A PATTERN";
}

现在我想创建一个接收字符串作为参数的方法。但是,我想强制程序员只使用class Permissions 中的strings

如果我使用枚举,这不会有问题,因为方法参数类型是明确定义的。

当我们使用泛型时,我们可以实现这种类型的约束。 有什么我不知道的“轻/快”可以让我在我的情况下这样做吗?

【问题讨论】:

  • 如果字符串看起来总是与 const 名称相同,为什么 使用枚举?当您需要字符串时,一个简单的 enum.ToString() 就可以了……您的“自定义参数类”会是什么样子,为什么会影响性能?
  • @RenéVogt:听起来 OP 可能正在实现一个接口或类似的接口,将它们限制在参数类型上。有更多信息会很好......
  • “出于性能原因,我没有添加自定义参数类来存储和读取它” - 我根本不明白这一点。如果您能在此处提供更多上下文,这将非常有帮助。
  • 您现在已经提到“反射是不涉及的”,但没有给我们关于如何参与的上下文。我添加了一个针对您当前选择的方法的答案,但如果没有更多上下文,我们无法建议可能更好的替代方法。
  • 如果您的程序确实 any 工作,那么“出于性能原因”不使用反射可能不是合理的推理。您可能希望实际测试您的理论并分析您拒绝的解决方案。与您的程序实际执行的操作 相比,反射的开销很小。

标签: c#


【解决方案1】:

我曾经多次遇到过这种情况。我几乎总是采用struct 方法。

首先你定义一个这样的结构:

public struct Permission : IEquatable<Permission>, IEquatable<string>
{
    private readonly string key;

    private Permission(string key)
    {
        this.key = key;
    }

    // implement Equals, GetHashCode, IEquatable...
}

然后你可以将你想要拥有的所有权限声明为结构的静态成员。

public class Permission
{
    // ...
    public static readonly First = new Permission("First");
}

现在,使用 struct 而不是 class 有一个主要优点和一个主要缺点:

  • 专业版:无需堆分配,无需指针取消引用。它尽可能快。
  • 缺点:即使我们声明了构造函数,私有结构总是有一个隐式的默认构造函数。它是不可见的,但数组默认用它初始化,default(T) 也是如此。

如果您决定使用结构,强烈建议添加以下方法/属性:

public bool IsEmpty
{
    get { return this.key == null; }
}

如果您决定使用类方法,则分配大部分会被保存,因为我不认为您将分配新实例而不是已声明为静态成员的实例,因此缺点实际上是额外的指针。

【讨论】:

  • 这似乎是在建议使用不同的参数类型,OP 明确表示不能这样做。 (诚​​然,上下文相对较少。)
  • @DaisyShipton 我不确定 OP 究竟是什么意思,因为性能原因,我建议使用 struct ,因为它们不会导致性能损失。
  • @DaisyShipton 是的,我说过要使用字符串(强制),但前提是我会坚持使用这种类型的解决方案,但我从未说过我不接受替代方案。
  • @Dryadwoods:当你不清楚你在问什么时会发生这种情况。真的很难说出你的约束到底是什么。
  • @Dryadwoods:您接受的答案并没有回答您实际提出的问题。这表明该问题并不能清楚地代表您的情况,IMO - 这意味着对于其他想要回答类似问题的人来说,它的用处要小得多。以后请尽量明确自己的要求——这个问题对其他读者来说会更有价值,而且你不会浪费别人的时间。
【解决方案2】:

不,语言中没有任何东西可以做到这一点。如果您可以避免这种情况,那么这样做会很好。当我们有更多的上下文时,我们可能会提出替代方案。

如果你真的使用这种方法,我建议先在方法中添加执行时验证,这样如果传入无效值,你会立即发现,而不是处理无效数据。

其次,您可以编写一个 Roslyn 分析器来查找您的方法的所有调用,并检查参数的格式是否正确。但是,如果您遇到这样的情况,这可能会导致问题:

public void Foo()
{
    FooImpl(Permissions.X1);
    DoSomethingElse();
}

private void FooImpl(string permission)
{
    RealMethodWithChecking(permission);
}

此时,您的 Roslyn 分析器将关闭,因为 RealMethodWithChecking 的参数并非直接来自 Permissions - 但它是一个本身来自 Permissions 的参数。这是否是一个问题,以及您决定如何解决它,在很大程度上取决于上下文。

【讨论】:

    猜你喜欢
    • 2015-02-16
    • 2019-10-27
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2022-07-29
    • 2010-12-13
    相关资源
    最近更新 更多