C# 什么';在不可变接口上公开可变接口的最佳方式是什么?

C# 什么';在不可变接口上公开可变接口的最佳方式是什么?,c#,inheritance,interface,properties,readonly,C#,Inheritance,Interface,Properties,Readonly,我想知道C#中关于可变/不可变接口的最佳实践是什么 我喜欢只针对接口而不是真实对象工作;删除依赖项并允许更轻松的测试 我还通常公开只读的接口,这样可以减少错误。 然而,当我需要更改对象实例上的内容时,这会在实际代码中产生问题 这就是我要做的 public interface ISomething { string Name { get; } } public interface IMutableSomething : ISomething { string Name {

我想知道C#中关于可变/不可变接口的最佳实践是什么

我喜欢只针对接口而不是真实对象工作;删除依赖项并允许更轻松的测试

我还通常公开只读的接口,这样可以减少错误。 然而,当我需要更改对象实例上的内容时,这会在实际代码中产生问题

这就是我要做的

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";
   }
}
通过这种方式,我可以轻松地测试ConsumerClass,并打破ISomething及其实现之间的任何依赖关系

我知道我可以将接口转换为实现,但这将引入对真实实现的依赖

我可以做下面这样的事情,但我觉得它又丑陋又烦人

public interface IMutableSomething : ISomething
{
    void SetName(string newName)   
}

or

public interface IMutableSomething // No inheritance, implementation impl. 2 interfaces
{
    string Name { get; set; }
}
谢谢


Eric G.

这并不是界面的正确使用;接口是这样的,您不必关心实现是什么,只需使用定义的属性和方法即可。如果需要“设置”某个具有get only接口的对象,则不应将该接口作为参数传递

在这种情况下,如果必须使用接口,请在接口上定义set方法(或以不同方式实现属性)


然后简单地让不可变接口不处理该值(或抛出异常)

我认为您的界面很好,但在您的消费代码中应该是这样的:

public class ConsumerClass{   
  // Just take IMutableSomething
  public void DoSomethingOnName(IMutableSomething o)   {       
    o.Name = "blah"; 
  }
}
方法调用是一个契约,正如其他人所说,您需要指定您的
ConsumerClass
实际可以使用的最通用类型。您可能需要阅读Liskov替换原则:


在这种情况下,虽然IMutableSomething可以代替ISomething,但反过来就不正确了。

我觉得有点可笑-您传递的是带有特定接口的内容(我认为这是“正确工作的最低要求”),然后将其强制转换为对其有进一步要求的对象(现在必须允许设置)。这有点像设定一个目标后,当有人达到目标后,说,哦,是的,顺便说一句,这不是目标后,这只是一个半途而废的markerIn补充,为了接口的接口并不是真的那么有用“我不确定你所建议的代码的目的是什么;如果有一个setter在调用时总是抛出,但却有一个Set方法进行设置,这似乎是一个糟糕的设计。我试图做的是类似于
var something=Repository.Get(…)
的事情,它将返回一个ISomething,然后调用
ConsumerClass.DoSomething(something)
无需在调用前强制转换为IMutableSomething。。。这样,我就不会不经意间改变名字了,这不是一个好主意。如果您需要IMutableSomething,您应该让您的存储库能够返回IMutableSomething。您尝试执行的操作只会导致用户出现运行时异常。如果您不想无意中更改ISomething,那么请在任何地方获取ISomethings,除非您确实需要更改名称。感谢您的输入。这基本上就是我要做的,在调用之前不必强制转换参数。
public class ConsumerClass{   
  // Just take IMutableSomething
  public void DoSomethingOnName(IMutableSomething o)   {       
    o.Name = "blah"; 
  }
}