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