What's the best way expose a mutable interface over an immutable one?
I wonder what's the best practice in C# regarding mutable / immutable interfaces.
I like to work against interfaces only instead of the real objects; remove dependencies and allow for easier testing.
I also usually expose interface that are read-only, which lower errors. however this is creating a problem in the actual code when I need to change things on the instance of the object.
Here's what I'm trying to do
public interface ISomething
{
string Name { get; }
}
public interface IMutableSomething : ISomething
{
string Name { get; set; }
}
...
public class ConsumerClass
{
//Note that I'm working against the interface, not the implementation
public void DoSomethingOnName(ISomething o)
{
var mutableO = (IMutableSomething) o;
mutableO.Name = "blah";
}
}
Working this way allows me to easily test ConsumerClass and break any dependency between the ISomething an开发者_如何转开发d it's implementation
I know that I could cast the interface to the implementation but this would introduce a dependency on the real implementation.
I could do something like below but I find it ugly and annoying
public interface IMutableSomething : ISomething
{
void SetName(string newName)
}
or
public interface IMutableSomething // No inheritance, implementation impl. 2 interfaces
{
string Name { get; set; }
}
Thanks,
Eric G.
I think your interfaces are fine, but in your consumer code it should look like this:
public class ConsumerClass{
// Just take IMutableSomething
public void DoSomethingOnName(IMutableSomething o) {
o.Name = "blah";
}
}
The method call is a contract, and as others have said you need to specify the most general type that your ConsumerClass
can actually use. You might want to read up on Liskov substitution principle: http://en.wikipedia.org/wiki/Liskov_substitution_principle.
In this case, while IMutableSomething can substitute for ISomething, the inverse is not true.
This isn't really the proper use of an interface; the interface is so that you don't care what implementation is, you simply use the defined properties and methods. If you need to 'set' something that has a get only interface, you should not be passing the interface as a parameter.
In this kind of situation, if you MUST go with an interface, define a set method on your interface (or implement the property differently)
public interface ISomething
{
string Name { get; set;}
void SetName(string newValue);
}
// Choose one of these methods to implement; both is overkill
public class SomethingElse : ISomething
{
protected string _internalThing = string.Empty;
public string Name
{
get { return _internalThing; }
set { throw new InvalidOperationException(); }
}
public void SetName(string newValue)
{
throw new InvalidOperationException();
}
}
And then simply have the immutable interfaces do nothing with the value (or throw an exception).
精彩评论