【问题标题】:Call Method overloaded from abstract class从抽象类重载的调用方法
【发布时间】:2013-08-30 12:22:49
【问题描述】:

我需要调用一个抽象类实现的方法。但是编译器总是默认使用具体类的重载方法,因为签名只需要一个继承的类型。

看看代码:

-- 这显然是我正在使用的实际代码的一个大大简化的版本;)

public class ModelBase { }
public class ModelA : ModelBase { }
public interface IInterface<in TModel>
{
    void Do(TModel model);
}
public abstract class AbstractClass<TModel> : IInterface<TModel>
{
    public abstract void Do(TModel model);
}
public class ConcreteClass : AbstractClass<ModelA>, IInterface<ModelBase>
{
    public override void Do(ModelA model)
    {
        // I'd like to invoke this method
    }

    public void Do(ModelBase model)
    {
        // how do I invoke the method above??
        Do((ModelA)model);
    }
}

^^ 这会导致递归

我试过的是:

((IClass<ModelA>)this).Do((ModelA)model);

^^ 不会改变任何东西

base.Do((ModelA)model);

^^ 抛出错误“无法调用抽象基成员:'AbstractClass.Do(ModelA)'”

如何调用“public override void Do(ModelA model)”方法?


顺便说一句。 如果我把课程改成这个

public class ConcreteClass : IInterface<ModelA>, IInterface<ModelBase>

它有效。

【问题讨论】:

  • 这看起来像是来自编译器重载解析器的错误......我错过了什么
  • 如果可以的话,为什么你有一个利用基本类型的重载,然后假设该类型是 ModelA 进行调用?设置过载的方式,我可以给你一个 ModelB。
  • 非常有效的问题@neoistheone。基本上我有一个正在请求的 IRepository 。交付了一个 ConcreteRepository。现在在 Repository 接口上调用了一个 Insert 方法。即使它是逆变的,我也不能将 IRepository 转换为 IRepository。因此,我必须将 IRepository 继承添加到具体存储库中。
  • 我认为发生这种情况的原因是来自重载决议规则,特别是来自7.5.5.1 of the C# specification "如果 N 适用于 A(第 7.4.2.1 节),则声明的所有方法在 T 的基类型中从集合中删除。" 在这种情况下, ConcreteClass 上的有效方法,并且您要调用的override 方法实际上属于到基地AbstractClass&lt;TModel&gt; 所以它被忽略了。编辑:重载规则也可能将这两种方法视为“同等适用”;不过不确定。
  • 我同意@ChrisSinclair。但没想到抽象方法的实现竟然被认为是基类的!

标签: c#


【解决方案1】:

在调用前将this 转换为AbstractClass&lt;ModelA&gt;

public void Do(ModelBase model)
{
    ((AbstractClass<ModelA>)this).Do((ModelA)model);
}

【讨论】:

  • 是的,打算发布同样的内容。这是了解基础方法与实例方法解析的好帖子:stackoverflow.com/questions/12110565/…
  • 谢谢!我与'((IClass)this).Do((ModelA)model);'非常接近:)
【解决方案2】:

使用命名参数:

public class ConcreteClass : AbstractClass<ModelA>, IInterface<ModelBase>
{
    public override void Do(ModelA modelA) // change 'model' into 'modelA'
    {
        // I'd like to invoke this method
    }

    public void Do(ModelBase model)
    {
        // how do I invoke the method above??
        Do(modelA : (ModelA)model);
    }
}

现在,编译器知道您要调用Do(ModelA) 方法而不是Do(ModelBase) 方法。

【讨论】:

    【解决方案3】:

    尝试显式地实现接口。从现在开始,您只能从 IInterface&lt;ModelBase&gt; 类型的引用中调用方法 IInterface&lt;ModelBase&gt;.Do(ModelBase model)

    public class ModelBase { }
    public class ModelA : ModelBase { }
    public interface IInterface<in TModel>
    {
        void Do(TModel model);
    }
    public abstract class AbstractClass<TModel> : IInterface<TModel>
    {
        public abstract void Do(TModel model);
    }
    public class ConcreteClass : AbstractClass<ModelA>, IInterface<ModelBase>
    {
        public override void Do(ModelA model)
        {
            Console.Write("Do - Override AbstractClass<ModelA> ");
        }
    
        void IInterface<ModelBase>.Do(ModelBase model)
        {
            Console.Write("Do - IInterface<ModelBase> ");
            Do(model as ModelA);
        }
    }
    
    void Main()
    {
        var modelA = new ModelA();
    
        (new ConcreteClass() as IInterface<ModelBase>).Do(modelA); //output -> Do - IInterface<ModelBase> Do - Override AbstractClass<ModelA> 
        Console.WriteLine();
        new ConcreteClass().Do(modelA); //output -> Do - Override AbstractClass<ModelA> 
    }
    

    【讨论】:

    • 谢谢。我实际上可能会选择这个解决方案。 :)
    • 顺便注意一下这个 Do(model as ModelA);因为您不能确定变量模型是 ModelA 的实例或其子类之一
    猜你喜欢
    • 2016-06-20
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    相关资源
    最近更新 更多