C#扩展接口实现作为委托接受基接口的参数

时间:2016-12-19 15:45:25

标签: c# inheritance interface

我有一个扩展其他界面的界面,如下所示:

interface IBase
{
  int Id { get; set; }
  string Name { get; set; }
}

interface IExtended : IBase
{
  bool IsChecked { get; set; }
}

然后我使用基接口作为委托函数中的参数,该委托函数也是类构造函数的参数,如下所示:

public class SomeClass
{
  private IBase _model;
  private Func<IBase, string> _handler;

  public SomeClass(IBase model, Func<IBase, string> handler)
  {
    _model = model;
    _handler = handler;
  }

  public string ExecuteHandler()
  {
    return _handler(model);
  }
}

接口实现:

public class BaseImplementation : IBase
{
  int Id { get; set; }
  string Name { get; set; }

  public BaseImplementation(int id, string name)
  {
    Id = id;
    Name = name;
  }
}

public class ExtendedImplementation : IExtended
{
  int Id { get; set; }
  string Name { get; set; }
  bool IsChecked { get; set; }

  public BaseImplementation(int id, string name, bool isChecked)
  {
    Id = id;
    Name = name;
    IsChecked = isChecked;
  }
}

预期用途:

BaseImplemetation baseModel = new BaseImplementation(1, "base");
ExtendedImplemetation extendedModel = new ExtendedImplementation(2, "extended", true);

SomeClass someClass1 = new SomeClass(baseModel, (IBase arg) => {
  Console.Write("Remember, " + arg.name + ", YOLO!");
});

SomeClass someClass2 = new SomeClass(extendedModel, (IExtended arg) => {
  Console.Write(arg.name + ", YOLO! You're " + (arg.IsChecked) ? "checked!" : "not checked!");
});

string res1 = someClass1.ExecuteHandler();
string res2 = someClass2.ExecuteHandler();

但是那个(不起作用,即使IExtended的实现必然会实现IBase接口定义的所有内容。为什么会这样,我如何绕过它并得到我想要的结果?

修改

我想我现在明白了。

我认为 Func<IBase, string> 等于 Func<IExtended, string> ,因为IExtended当然会实现IBase所做的一切,所以应该没有问题,对?我希望它实现并且在我的示例中列出的实现当然可以正常工作。

BUT!问题是someClass2不能像这样构造,因为正如@Servy所提到的,委托函数可以做这样的事情:

SomeClass someClassWrong = new SomeClass(baseModel, (IExtended arg) => {
  if (arg.IsChecked) {
    // gotcha, baseModel doesn't have IsChecked property!
  }
});

编辑2:

感谢大家的帮助和对不起的不断编辑,并给出了我想要的错误示例:D

3 个答案:

答案 0 :(得分:3)

  

但这不起作用,即使IExtended的实现必然会实现IBase接口定义的所有内容。为什么会这样,我将如何绕过这个并得到我想要的结果呢?

SomeClass调用该委托时,它可能实际上没有传递IExtended实例。允许提供任何 IBase实例作为参数,因此,如果它提供实现IExtended的实例,那么您会期望什么?你的代表要做什么?

如果SomeClass 总是要传递IExtended实例,那么相应地修改它在构造函数中接受的委托,以便调用者始终知道他们正在获取IExtended实例作为参数。

答案 1 :(得分:0)

您只需定义知道的代理 IBase实际上是IExtended

SomeClass someClass = new SomeClass((IBase arg) => { (arg as IExtended).DoSomethingOnlyExtendedKnowsAbout(); });

这可能是不安全的,但是如果你以某种方式强制执行传递给特定lamda的arg将始终是IExtended那么就没有坏处。您还可以在lambda中提供一个安全机制,并在调用堆栈中相应地管理它:

SomeClass someClass = new SomeClass((IBase arg) => { (arg as IExtended)?.DoSomethingOnlyExtendedKnowsAbout(); });

答案 2 :(得分:0)

我没有看到问题所在。根据您拥有的代码,以下内容按预期工作:

public class SomeClass
{
    public SomeClass(Func<IBase, string> handlerFcn)
    {
        // something gets done
        this.Handler=handlerFcn;
    }
    public Func<IBase, string> Handler { get; set; }
}

public static class Program
{
    static void Main(string[] args)
    {
        var s1 = new SomeClass((x) => x.SomeMethod());
        var xt = new ExtendedClass();
        var result = s1.Handler(xt);
        // result = "yolo extended edition!"
    }
}

我认为你试图在lambda定义中使用具体的类ExtendedClass,除非你define it as a closure,否则它不会起作用。