views:

567

answers:

4

I have a set of interfaces which are used in close conjunction with particular mutable object.

Many users of the object only need the ability to read values from the object, and then only a few properties. To avoid namespace pollution (easier intellisense) and to get across the usage intent, I'd like to have a small base interface which only exposes a few "key" properties in a read-only fashion.

However, almost all implementations will support the full interface, which includes modifiability.

Unfortunately, I ran into a roadblock expressing that concept in C#:

interface IBasicProps {
   public int Priority { get; }
   public string Name {get;}
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   public int Priority { set; } //warning CS0108: [...] hides inherited member [...]
   public string Name { set; }
   //... whatever
}

I certainly wasn't intending to hide any members, so that aint good!

Of course, I can solve this using methods just fine, but what's the right choice? I'd like to keep the "core" interface as small as possible even if splitting the interfaces serves no purpose other than communicating intent. With split interfaces, it's just really obvious which methods aren't going to do any updating, and it makes writing code a bit clearer (not to mention also allows nice-n-simple static singleton stubs that suffice for quite a few simple cases).

I'd like to avoid any abstract classes and the like; they make reimplementation or quick single-purpose shims all that more complex and hard-to-grok.

So, ideas?

+8  A: 

Method hiding in an interface isn't nearly as grungy; I'd go with something like:

interface IBasicProps {
   int Priority { get; }
   string Name {get;}
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   new int Priority { get; set; }
   new string Name { get; set; }
   //... whatever
}
class Foo : IBasicPropsWriteable {
    public int Priority {get;set;}
    public string Name {get;set;}
/* optional
    int IBasicProps.Priority {get {return Priority;}}
    string IBasicProps.Name {get {return Name;}}
*/
}
Marc Gravell
As a bonus, this actually works well with co/contravariance too; My actual use case is more like `IBasicProps<out T> {/*...*/ } IBasicPropsWriteable<T>:IBasicProps<T> {}`. Here the interface split is necessary; a central manager would like covariance to put various objects in one collection, but the individual owners of each object know what type it contains.
Eamon Nerbonne
+3  A: 

If your goal is to make it clearer when reading vs. writing is allowed, then I would use separate getter and setter methods rather than properties.

interface IBasicProps {
   int GetPriority();
   string GetName();
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   void SetPriority(int priority);
   void SetName(string name);
   //... whatever
}
Jeffrey L Whitledge
This ain't a beauty-contest winner, but it looks like it's a pretty safe bet it'll work fine...
Eamon Nerbonne
+1  A: 

One way could be to simply skip the inheritance of the interfaces. Make one read-only interface and one write-only, and implement as necessary:

interface IBasicPropsReadable {
   int Priority { get; }
   string Name { get; }
}

interface IBasicPropsWriteable  {
   int Priority { set; }
   string Name { set; }
}

class SomeClassReadWrite : IBasicPropsReadable, IBasicPropsWriteable {
    int Priority { get; set; }
    string Name { get; set; }
}

class SomeClassReadOnly : IBasicPropsReadable {
    int Priority { get; }
    string Name { get; }
}
Fredrik Mörk
This won't let me express the common notion of "a read/write object". How can I write a method which accepts only read/write variants, now?
Eamon Nerbonne
+1  A: 

You could leave the interfaces unrelated and simply have your class implement both interfaces. After all the interfaces are simply defining the contract and the contracts don't need to be related. It seems like it just an optimization for you when coding to have the writeable one derive from the other, so you only have to specify one interface.

public interface IBasicProps
{
   int Priority { get; }
   string Name {get;}
   //... whatever
}

public interface IBasicPropsWriteable
{
   int Priority { get; set; }
   string Name { get; set; }
   //... whatever
}

public class Foo : IBasicProps, IBasicPropsWriteable
{
   public int Priority { get; set; }
   public string Name { get; set; }

   // whatever
}

If you really needed the optimization, you could create another interface that derives from both and have your classes implement that.

public interface IBasicPropsAll : IBasicProps, IBasicPropsWriteable  { }

public class Foo : IBasicPropsAll
{
   public int Priority { get; set; }
   public string Name { get; set; }

   // whatever
}
tvanfosson
The IBasicPropsAll approach doesn't work (very well). `((IBasicPropsAll)new Foo()).Name` is ambiguous, and the compiler won't accept it. This means you need to cast commonly.
Eamon Nerbonne
Yes. You'd only use this to get the "optimization" of not having to type both interfaces. I'm not recommending it. You wouldn't actually use it, you'd cast to either of IBasicProps or IBasicPropsWriteable in practice.
tvanfosson