在不可变接口上公开可变接口的最佳方法是什么?

发布于 2024-11-05 16:18:25 字数 979 浏览 4 评论 0原文

我想知道 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.

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 and 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一向肩并 2024-11-12 16:18:25

我认为你的接口很好,但在你的消费者代码中它应该是这样的:

public class ConsumerClass{   
  // Just take IMutableSomething
  public void DoSomethingOnName(IMutableSomething o)   {       
    o.Name = "blah"; 
  }
}

方法调用是一个契约,正如其他人所说,你需要指定你的 ConsumerClass 实际上可以的最通用的类​​型使用。您可能想阅读里氏替换原则:http://en.wikipedia.org/wiki/Liskov_substitution_principle< /a>.

在这种情况下,虽然 IMutableSomething 可以替代 ISomething,但反之则不然。

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.

不弃不离 2024-11-12 16:18:25

这实际上并不是接口的正确使用方式;接口使您不必关心实现是什么,您只需使用定义的属性和方法即可。如果您需要“设置”具有仅获取接口的内容,则不应将该接口作为参数传递。

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

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();
     }
}

,然后简单地让不可变接口对值不执行任何操作(或抛出异常)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文