alexpanter
alexpanter

Reputation: 1578

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:

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.

Upvotes: 3

Views: 3194

Answers (2)

alexpanter
alexpanter

Reputation: 1578

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!

Upvotes: 0

Arsen Mkrtchyan
Arsen Mkrtchyan

Reputation: 50742

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;
}

Upvotes: 3

Related Questions