简体   繁体   中英

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). To avoid code duplication, I wanted to create an interface for classes that need an api key.

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. 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 . (const, but can be set in the constructor)
  • 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.
  • 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++:

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

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. The best thing would be allow decorating the interface's 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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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