C# 如何从超类中调用两个子类的公共名称方法?

C# 如何从超类中调用两个子类的公共名称方法?,c#,class,C#,Class,在日常工作中,我遇到了一个问题: 假设: 我们有一个对象a,它是object类型 A可能是类型B或类型C 类型B和C具有相同的名称方法GetSomething() 我们不知道B和C是否都实现了相同的接口(这意味着我们不知道它们之间的关系) 键入B和C继承自Object,这意味着没有任何帮助。除了相同的方法名称之外,我们对类型B和C一无所知 问题是,我想从A调用GetSomething,无论它是什么类型: //Object A maybe type B or C //both B and C ca

在日常工作中,我遇到了一个问题:

假设:

  • 我们有一个对象a,它是
    object
    类型
  • A可能是类型
    B
    或类型
    C
  • 类型
    B
    C
    具有相同的名称方法
    GetSomething()
  • 我们不知道
    B
    C
    是否都实现了相同的接口(这意味着我们不知道它们之间的关系)
  • 键入
    B
    C
    继承自
    Object
    ,这意味着没有任何帮助。除了相同的方法名称之外,我们对类型
    B
    C
    一无所知
  • 问题是,我想从A调用
    GetSomething
    ,无论它是什么类型:

    //Object A maybe type B or C
    //both B and C can call method
    //but we just don't know type of A
    var result=A.GetSomething();
    

    如果您遇到这种情况,您会怎么做?

    这似乎需要一种抽象方法

    public abstract class A {
       protected abstract object GetSomething();
    }
    
    在每个派生类中,您需要实现GetSomething(),例如

    然后,您可以在超类(
    A
    )实现中的任意位置自由调用
    GetSomething()

    如果您不想在超级类的实现中调用它,但在其他地方,您基本上有三种选择

    • 更改超类的实现以包含方法的(潜在抽象)定义
    • 使用动态类型
    • 使用反射
    前者基本上与上述示例相同(只需将访问修饰符
    设置为public
    ,而不是
    protected

    第二和第三种选择都有同样的缺点。它们不是编译时类型的,所以在开发过程中,您可能(将)偶尔会出现运行时错误,而不是编译时错误。如果你有一个很高的测试覆盖率,这应该不是一个太大的问题

    我更喜欢使用动态类型,因为它比反射版本更容易读写。假设
    GetSomething
    返回一个int,它将如下所示

    int result=((动态)A).GetSomething()


    我已将结果更改为显式类型而不是隐式类型,因为否则它将被类型化为
    dynamic
    ,导致任何涉及结果的表达式也被类型化为dynamic。如果您知道
    GetSomething
    的返回类型,最好事先告诉编译器这似乎需要一个抽象方法

    public abstract class A {
       protected abstract object GetSomething();
    }
    
    在每个派生类中,您需要实现GetSomething(),例如

    然后,您可以在超类(
    A
    )实现中的任意位置自由调用
    GetSomething()

    如果您不想在超级类的实现中调用它,但在其他地方,您基本上有三种选择

    • 更改超类的实现以包含方法的(潜在抽象)定义
    • 使用动态类型
    • 使用反射
    前者基本上与上述示例相同(只需将访问修饰符
    设置为public
    ,而不是
    protected

    第二和第三种选择都有同样的缺点。它们不是编译时类型的,所以在开发过程中,您可能(将)偶尔会出现运行时错误,而不是编译时错误。如果你有一个很高的测试覆盖率,这应该不是一个太大的问题

    我更喜欢使用动态类型,因为它比反射版本更容易读写。假设
    GetSomething
    返回一个int,它将如下所示

    int result=((动态)A).GetSomething()


    我已将结果更改为显式类型而不是隐式类型,因为否则它将被类型化为
    dynamic
    ,导致任何涉及结果的表达式也被类型化为dynamic。如果您知道
    GetSomething
    的返回类型,那么最好事先告诉编译器如果
    A
    没有该方法,那么您不应该考虑这样做,因为这是一种糟糕的设计,违反了OOP原则。但是,如果您必须这样做,您可以尝试使用反射:

    MethodInfo methodInfo = this.GetType().GetMethod("GetSomething", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
    if(methodInfo != null)
       result = methodInfo.Invoke(this, new object[] {});
    

    但是,我强烈建议您在
    a
    类中使用抽象类或默认的
    GetSomething()

    如果
    a
    没有该方法,您不应该考虑这样做,因为这是一种糟糕的设计,违反了OOP原则。但是,如果您必须这样做,您可以尝试使用反射:

    MethodInfo methodInfo = this.GetType().GetMethod("GetSomething", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
    if(methodInfo != null)
       result = methodInfo.Invoke(this, new object[] {});
    
    但是,我强烈建议在
    a
    类中使用抽象类或默认的
    GetSomething()

    • 类型B和C具有相同的名称方法GetSomething()
    • 我们不知道B和C是否都实现了相同的接口
    你不知道,但你能改变它吗?因为最合乎逻辑的解决方案是描述接口中的“某物”行为:

    interface IHasSomething
    {
        Something GetSomething();
    }
    
    var something = obj as IHasSomething
    if (something != null)
    {
        var youWereLookingFor = something.GetSomething();
    }
    
    把它应用到B类和C类

    假设您的B和C实例被声明为
    对象
    ,您可以尝试测试它们是否实现此接口:

    interface IHasSomething
    {
        Something GetSomething();
    }
    
    var something = obj as IHasSomething
    if (something != null)
    {
        var youWereLookingFor = something.GetSomething();
    }
    
    或者您可以尝试使用反射,这应该是与良好的OO设计相对应的最后手段(如果您想要添加参数和/或重载,调用另一个方法,使用不同的返回类型,等等)

    • 类型B和C具有相同的名称方法GetSomething()
    • 我们不知道B和C是否都实现了相同的接口
    你不知道,但你能改变它吗?因为最合乎逻辑的解决方案是描述接口中的“某物”行为:

    interface IHasSomething
    {
        Something GetSomething();
    }
    
    var something = obj as IHasSomething
    if (something != null)
    {
        var youWereLookingFor = something.GetSomething();
    }
    
    把它应用到B类和C类

    假设您的B和C实例被声明为
    对象
    ,您可以尝试测试它们是否实现此接口:

    interface IHasSomething
    {
        Something GetSomething();
    }
    
    var something = obj as IHasSomething
    if (something != null)
    {
        var youWereLookingFor = something.GetSomething();
    }
    
    或者你也可以尝试使用反射,作为最后的手段