简体   繁体   English

如何拥有只读成员的 C# 接口

[英]How to have C# interface with readonly member

Interface inconvenience接口不便

I recently found myself in need of something, which should very much be possible in C# (I know it is in C++): Several classes need an api key, which absolutely has to be a private, immutable field (except for being declared in the constructor).我最近发现自己需要一些东西,这在 C# 中应该是非常可能的(我知道它在 C++ 中):几个类需要一个 api 密钥,它绝对必须是一个私有的、不可变的字段(除了在构造函数)。 To avoid code duplication, I wanted to create an interface for classes that need an api key.为了避免代码重复,我想为需要 api 密钥的类创建一个接口。

I will let the code speak for itself:我会让代码不言自明:

public interface IHasApiKey
{
    protected readonly string _apiKey = String.Empty;
}

Problems:问题:

  • I could let it be a class instead, since interfaces cannot instantiate member attributes.我可以让它成为一个类,因为接口不能实例化成员属性。 But since C# does not allow multiple inheritance, and since I consider this feature a behaviour rather than an implementation, I can't see why it shouldn't be an interface.但是由于 C# 不允许多重继承,而且我认为这个特性是一种行为而不是一种实现,我不明白为什么它不应该是一个接口。 And it might clash with classes which already have a base class.它可能会与已经有基类的类发生冲突。
  • I could convert it into a property, but no matter the accessibility level, if it is inherited, it can still be modified in methods of derived classes, whereas I really want the behaviour of readonly .我可以将其转换为属性,但是无论可访问性级别如何,如果它是继承的,仍然可以在派生类的方法中进行修改,而我真的想要readonly的行为。 (const, but can be set in the constructor) (const,但可以在构造函数中设置)
  • I discovered the attribute System.ComponentModel.ReadOnlyAttribute , but documentation is very limited, and it doesn't look like it performs like readonly , but more like an attribute which can be queried for in user code.我发现了属性System.ComponentModel.ReadOnlyAttribute ,但文档非常有限,它看起来不像readonly那样执行,而更像是可以在用户代码中查询的属性。
  • If I convert it to an auto-property, then all derived classes need to specify a private data member to point to, which again means duplicate code (which I try to avoid by having this interface in the first place)如果我将其转换为自动属性,则所有派生类都需要指定要指向的私有数据成员,这又意味着重复代码(我首先尝试通过使用此接口来避免这种情况)

For completeness' sake, here is what I imagine the correct code would look like in C++:为了完整起见,这里是我想象的正确代码在 C++ 中的样子:

class IHasApiKey
{
private:
    std::string _apiKey = "";
protected:
    IHasApiKey(const std::string& apiKey) : _apiKey(apiKey) {}

    // tbo, I'm not quite sure about how to optimally write this one,
    // but the idea is the same: provide protected read access.
    const std::string& GetKey() { return const_cast<std::string&>(_apiKey); }
};

Do I explain properly?我解释得对吗? And does anyone have an idea of how to solve this elegantly?有没有人知道如何优雅地解决这个问题? Thanks a lot in advance.非常感谢。

C# interfaces don't have a state, you can't declare field in interface non writable non read only. C# 接口没有状态,您不能在接口不可写非只读中声明字段。 And it turns out that for keeping a state you need class, so in your case it should be base class, or concrete one...事实证明,为了保持状态,您需要类,因此在您的情况下,它应该是基类或具体类...

One way to go is to declare a get property in interface, which will force all classes that implement this interface to provide get一种方法是在接口中声明一个 get 属性,这将强制实现该接口的所有类提供 get

public interface IHasApiKey
{
    string ApiKey {get;}
}

and classes should look like this和类应该是这样的

public class SomeFoo : IHasApiKey
{
    private readonly string _apiKey;
    public SomeFoo(string apiKey)
    {
        _apiKey = apiKey;
    }

    public string ApiKey => _apiKey;
}

Update [Closed]更新 [关闭]

It seems I am limited by my choice of language.看来我受语言选择的限制。 C# has no way of accomplishing what I want. C# 没有办法完成我想要的。 The best thing would be allow decorating the interface's setter:最好的办法是允许装饰界面的 setter:

public interface IHasApiKey
{
    protected string _apiKey { get; readonly set; }
}

But likely that would require impossible changes to the compiler, and likely break with the language design.但这可能需要对编译器进行不可能的更改,并且可能会破坏语言设计。 I find it unlikely that it will ever be added.我发现它不太可能被添加。

Thank you everyone who took their time to think about this!感谢所有花时间考虑这个问题的人!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM