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

C#扩展接口实现,作为接受基本接口的委托的参数,c#,inheritance,interface,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;

我有一个扩展其他接口的接口,如下所示:

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);
  }
}
SomeClass someClassWrong = new SomeClass(baseModel, (IExtended arg) => {
  if (arg.IsChecked) {
    // gotcha, baseModel doesn't have IsChecked property!
  }
});
然后,我将基接口用作委托函数中的参数,委托函数也是类构造函数的参数,如下所示:

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);
  }
}
SomeClass someClassWrong = new SomeClass(baseModel, (IExtended arg) => {
  if (arg.IsChecked) {
    // gotcha, baseModel doesn't have IsChecked property!
  }
});
预期用途:

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
等于
Func
,因为IExtended当然实现了IBase所做的一切,所以应该没有问题,对吧?按照我希望的方式实现,并在我的示例中列出,当然会很好

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

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);
  }
}
SomeClass someClassWrong = new SomeClass(baseModel, (IExtended arg) => {
  if (arg.IsChecked) {
    // gotcha, baseModel doesn't have IsChecked property!
  }
});
编辑2:

谢谢大家对我的帮助,也很抱歉不断地编辑和给出我想要的:D的错误示例

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

SomeClass
调用该委托时,它可能实际上不会传递一个
IExtended
实例。它可以提供任何
IBase
实例作为参数,因此如果它提供一个未实现
IExtended
的实例,那么您希望委托做什么


如果
SomeClass
总是要传递一个
IExtended
实例,那么相应地修改它在构造函数中接受的委托,以便调用方总是知道他们得到了一个
IExtended
实例作为参数。

您可以简单地定义一个委托,该委托知道
IBase
实际上是一个
I扩展的

SomeClass someClass = new SomeClass((IBase arg) => { (arg as IExtended).DoSomethingOnlyExtendedKnowsAbout(); });
这可能是不安全的,但如果您可以强制执行传递给该特定lamda的
arg
始终是一个
ieextended
,则不会有任何危害。您还可以在lambda本身中提供一个安全机制,并在调用堆栈中对其进行相应的管理:

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

我看不出有什么问题。根据您拥有的代码,以下功能可以正常工作:

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!"
    }
}
公共类SomeClass
{
公共类(Func handlerFcn)
{
//做点什么
this.Handler=handlerFcn;
}
公共函数处理程序{get;set;}
}
公共静态类程序
{
静态void Main(字符串[]参数)
{
var s1=新的SomeClass((x)=>x.SomeMethod());
var xt=新的扩展类();
var result=s1.Handler(xt);
//result=“yolo扩展版!”
}
}

我认为您试图在lambda定义中使用具体类
ExtendedClass
,除非您这样做,否则这不会起作用。

委托应该始终只使用IBase中定义的方法(因此在本例中为IBase.SomeMethod())在某个类内部。IExtended中定义的其他方法在应用程序的其他部分中使用,但在这种特定情况下,我也希望将现有委托与IExtended实现一起使用。@DekiChan如我所说,调用委托时传递给委托的实际对象总是
IExtended
实例,在这种情况下,您需要d更改您正在接受或不接受的委托,并且提供委托的代码不能假定它们是
IExtended
实例。您不能提供
IBase
对象,这些对象不是
IExtended
并获得
IExtended
行为。我扩展了我的问题,希望能更清楚地解释我将要做的事情ike to do.@DekiChan在您的示例中,在这两种情况下,您都提供了一个不接受参数并返回
字符串的方法。如果这是您想要支持的,那么这就是您的代理签名应该是的。我知道我仍然没有解释我真正想要做什么。但我想首先我需要好好睡一觉,因为ob很明显,我的大脑目前功能不太好。但谢谢你,到目前为止,我明天会回来。如果你总是要传递一个扩展的
ieextended
,那么你应该只是更改代理签名。@Servy不知道完整的场景,情况并不总是这样。也许这个具体的
SomeClass
总是会收到
扩展了
参数,但
IBaseClass通常不会。回答演示了如果构造正确,这是如何实现类型安全的。感谢您的帮助,当我试图让它更清晰时,我问了一个错误的问题-我再次编辑了它并解释了一切。我想现在我想知道我想要的是什么,什么是错误的:)