gpt4 book ai didi

c# - 解决 'Virtual method call in constructor' 问题

转载 作者:IT王子 更新时间:2023-10-29 04:43:35 24 4
gpt4 key购买 nike

我正在用 C# 开发一个软件。我正在使用一个抽象类 Instruction,它具有以下代码:

protected Instruction(InstructionSet instructionSet, ExpressionElement newArgument,
bool newDoesUseArgument, int newDefaultArgument, int newCostInBytes, bool newDoesUseRealInstruction) {

//Some stuff

if (DoesUseRealInstruction) {
//The warning appears here.
RealInstruction = GetRealInstruction(instructionSet, Argument);
}
}

public virtual Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument) {
throw new NotImplementedException("Real instruction not implemented. Instruction type: " + GetType());
}

因此 Resharper 告诉我,在标记的行中,我正在“在构造函数中调用虚拟方法”,这很糟糕。我了解有关调用构造函数的顺序的事情。 GetRealInstruction 方法的所有重写如下所示:

public override Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument) {
return new GoInstruction(instructionSet, argument);
}

所以他们不依赖类中的任何数据;他们只是返回一些依赖于派生类型的东西。 (因此构造函数顺序不会影响它们)。

那么,我应该忽略它吗?我宁愿不;那么谁能告诉我如何避免这个警告?

我不能巧妙地使用委托(delegate),因为 GetRealInstruction 方法还有一个重载。

最佳答案

我已经多次遇到这个问题,我发现正确解决它的最佳方法是将从构造函数调用的虚拟方法抽象到一个单独的类中。然后将这个新类的实例传递给原始抽象类的构造函数,每个派生类将其自己的版本传递给基构造函数。解释起来有点棘手,所以我将根据您的例子举一个例子。

public abstract class Instruction
{
protected Instruction(InstructionSet instructionSet, ExpressionElement argument, RealInstructionGetter realInstructionGetter)
{
if (realInstructionGetter != null)
{
RealInstruction = realInstructionGetter.GetRealInstruction(instructionSet, argument);
}
}

public Instruction RealInstruction { get; set; }

// Abstracted what used to be the virtual method, into it's own class that itself can be inherited from.
// When doing this I often make them inner/nested classes as they're not usually relevant to any other classes.
// There's nothing stopping you from making this a standalone class of it's own though.
protected abstract class RealInstructionGetter
{
public abstract Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument);
}
}

// A sample derived Instruction class
public class FooInstruction : Instruction
{
// Passes a concrete instance of a RealInstructorGetter class
public FooInstruction(InstructionSet instructionSet, ExpressionElement argument)
: base(instructionSet, argument, new FooInstructionGetter())
{
}

// Inherits from the nested base class we created above.
private class FooInstructionGetter : RealInstructionGetter
{
public override Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument)
{
// Returns a specific real instruction
return new FooRealInstuction(instructionSet, argument);
}
}
}

// Another sample derived Instruction classs showing how you effictively "override" the RealInstruction that is passed to the base class.
public class BarInstruction : Instruction
{
public BarInstruction(InstructionSet instructionSet, ExpressionElement argument)
: base(instructionSet, argument, new BarInstructionGetter())
{
}

private class BarInstructionGetter : RealInstructionGetter
{
public override Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument)
{
// We return a different real instruction this time.
return new BarRealInstuction(instructionSet, argument);
}
}
}

在您的特定示例中,它确实有点令人困惑,我开始用尽合理的名称,但这是因为您已经在指令中嵌套了指令,即指令具有 RealInstruction(或至少可选地做);但如您所见,仍然可以实现您想要的并避免从构造函数调用任何虚拟成员。

如果仍然不清楚,我还会举一个基于我最近在自己的代码中使用的示例。在这种情况下,我有 2 种类型的表单,标题表单和消息表单,它们都继承自基本表单。所有表单都有字段,但每种表单类型都有不同的构造其字段的机制,所以我最初有一个名为 GetOrderedFields 的抽象方法,我从基构造函数中调用它,并且该方法在每个派生表单类中被重写。这给了我你提到的 resharper 警告。我的解决方案与上面的模式相同,如下所示

internal abstract class FormInfo
{
private readonly TmwFormFieldInfo[] _orderedFields;

protected FormInfo(OrderedFieldReader fieldReader)
{
_orderedFields = fieldReader.GetOrderedFields(formType);
}

protected abstract class OrderedFieldReader
{
public abstract TmwFormFieldInfo[] GetOrderedFields(Type formType);
}
}

internal sealed class HeaderFormInfo : FormInfo
{
public HeaderFormInfo()
: base(new OrderedHeaderFieldReader())
{
}

private sealed class OrderedHeaderFieldReader : OrderedFieldReader
{
public override TmwFormFieldInfo[] GetOrderedFields(Type formType)
{
// Return the header fields
}
}
}

internal class MessageFormInfo : FormInfo
{
public MessageFormInfo()
: base(new OrderedMessageFieldReader())
{
}

private sealed class OrderedMessageFieldReader : OrderedFieldReader
{
public override TmwFormFieldInfo[] GetOrderedFields(Type formType)
{
// Return the message fields
}
}
}

关于c# - 解决 'Virtual method call in constructor' 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17991419/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com