3
\$\begingroup\$

I'm trying to design a generic caching system that takes keyed items and allows either read-only or read-write access to a cached version of it. The read-only backing interface is:

public interface IReadableItem<TKey>
{
  TKey Key { get; }
}

However, I need to be able to dynamically update the key of my writable items. I've come up with two options, but both are unappealing.

I can forgo the inheritance:

public interface IWritableItem<TKey>
{
  TKey Key { get; set; }
}

... but this leaves me in a situation where I have to specify that every class is both an IWritableItem and an IReadableItem in order to allow read-write access.

On the other hand, I can use the new keyword to override the underlying inheritence:

public interface IWritableItem<TKey> : IReadableItem<TKey>
{
  new TKey Key { get; set; }
}

... but this leaves me with a bad code-smell, especially when attempting to explicitly implement the interface at the class level.

Is this a situation where I should just take the lesser of two evils, or is there a Third Way?

\$\endgroup\$

closed as off-topic by Jeff Vanzella, Jamal, Mathieu Guindon, ChrisWue, Brian Reichle Oct 17 '13 at 20:49

If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ Why don't you have a third interface IKeyItem<TKey> which declares the key. Your interfaces would then be IReadableItem<TKey> : IKeyItem<TKey> and IWriteableItem<TKey> : IKeyItem<TKey>. This will allow you to have readable, and writable classes without the complexity of having to new Key. I think this will clean up the code smell you are sensing. \$\endgroup\$ – Jeff Vanzella Oct 17 '13 at 16:17
  • \$\begingroup\$ @JeffVanzella: The issue is that IReadableItems should not be able to set the value of the Key, so moving it to a third interface doesn't actually address the issue. \$\endgroup\$ – Andrew Coonce Oct 17 '13 at 16:20
  • 4
    \$\begingroup\$ This is a design question and should be posted on Programmers \$\endgroup\$ – Jeff Vanzella Oct 17 '13 at 16:20
  • \$\begingroup\$ Maybe the setter is private in the class? Then you could have a Method `UpdateKey(TKey key) which could do some checking: i.e. they key isn't already set, then set the key through the private setter. \$\endgroup\$ – Jeff Vanzella Oct 17 '13 at 16:29
  • \$\begingroup\$ @JeffVanzella: I was hoping to keep using properties... this definitely feels more like a property than a method. Regarding the Programmer's comment, is there a way to migrate questions? \$\endgroup\$ – Andrew Coonce Oct 17 '13 at 16:32
1
\$\begingroup\$

What I would do is to use inheritance, but have only setter in IWritableItem:

public interface IReadableItem<TKey>
{
    TKey Key { get; }
}

public interface IWritableItem<TKey> : IReadableItem<TKey>
{
    new TKey Key { set; }
}

This still works as expected:

class Foo<T> : IWritableItem<T>
{
    public T Key { get; set; }
}

It also has the advantage that you can't implement the getter for IWritableItem differently from the getter for IReadableItem.

\$\endgroup\$
  • 1
    \$\begingroup\$ The drawback here is that if you pass a method an IWritableItem<T> then it can only access the Key.set, and not the Key.get. \$\endgroup\$ – Andrew Coonce Oct 17 '13 at 19:08
  • \$\begingroup\$ @AndrewCoonce You're right, I didn't think of that. \$\endgroup\$ – svick Oct 17 '13 at 19:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.