簡體   English   中英

C#-基於參數類型的不同功能覆蓋

[英]c# - different function override based on parameters' type

我在玩AST ,我想實現一個遍歷我的樹並返回值的Visitor類。 我以這種方式嘗試過,但是我的代碼無法編譯:

abstract class ASTVisitor<T> {
  public abstract T Visit(SumExpr e);
  public abstract T Visit(ProductExpr e);
  public abstract T Visit(ConstantExpr e);
  public abstract T Visit(SymbolExpr e); 
}

class DerivateVisitor : ASTVisitor<ASTExpr> {

  public override ASTExpr Visit(SumExpr e){
    return new SumExpr(
      Visit(e.A),
      Visit(e.B));
  }
  public override ASTExpr Visit(ProductExpr e){
    return new SumExpr(
      new ProductExpr(Visit(e.A), e.B),
      new ProductExpr(Visit(e.B), e.A));
  }
  public override ASTExpr Visit(ConstantExpr e){
    return new ConstantExpr(0);
  }
  public override ASTExpr Visit(SymbolExpr e) {
    return new ConstantExpr(1);
  }
}

SumExprProductExprConstantExprSymbolExpr實現:

class ASTExpr{}
class ProductExpr : ASTExpr{
  public ASTExpr A, B;
  public ProductExpr(ASTExpr a, ASTExpr b) => 
    (A, B) = (a, b);
  public override string ToString() => $"({A.ToString()}) * ({B.ToString()})";    

}

class ConstantExpr : ASTExpr {
  public double Value;
  public ConstantExpr(double v) => Value = v;
  public override string ToString() => Value.ToString();

}

class SymbolExpr : ASTExpr {
  public string Name;
  private static Dictionary<string, SymbolExpr> Symbols = new Dictionary<string, SymbolExpr>();
  private SymbolExpr(string v) { 
    Name = v;
  }

  public static SymbolExpr Create(string Name){
    if(Symbols.ContainsKey(Name)) return Symbols[Name];
    return Symbols[Name] = new SymbolExpr(Name);
  }

  public override string ToString() => $"Symbol({Name})";

}

class SumExpr : ASTExpr{
  public ASTExpr A, B;
  public SumExpr(ASTExpr a, ASTExpr b) => 
    (A, B) = (a, b);

  public override string ToString() => $"({A.ToString()}) + ({B.ToString()})";
}

SumExprProductExprConstantExprSymbolExpr繼承自ASTExpr 為什么這不起作用? 以及如何獲得這種行為?

這是編譯錯誤:

exit status 1
main.cs(56,7): error CS1502: The best overloaded method match for `ASTVisitor<ASTExpr>.Visit(SumExpr)' has some invalid arguments
main.cs(45,21): (Location of the symbol related to previous error)
main.cs(56,13): error CS1503: Argument `#1' cannot convert `ASTExpr' expression to type `SumExpr'
main.cs(57,7): error CS1502: The best overloaded method match for `ASTVisitor<ASTExpr>.Visit(SumExpr)' has some invalid arguments
main.cs(45,21): (Location of the symbol related to previous error)
main.cs(57,15): error CS1503: Argument `#1' cannot convert `ASTExpr' expression to type `SumExpr'
main.cs(61,23): error CS1502: The best overloaded method match for `ASTVisitor<ASTExpr>.Visit(SumExpr)' has some invalid arguments
main.cs(45,21): (Location of the symbol related to previous error)
main.cs(61,31): error CS1503: Argument `#1' cannot convert `ASTExpr' expression to type `SumExpr'
main.cs(62,23): error CS1502: The best overloaded method match for `ASTVisitor<ASTExpr>.Visit(SumExpr)' has some invalid arguments
main.cs(45,21): (Location of the symbol related to previous error)
main.cs(62,31): error CS1503: Argument `#1' cannot convert `ASTExpr' expression to type `SumExpr'
Compilation failed: 8 error(s), 0 warnings

預先感謝。

問題是

class SumExpr : ASTExpr
{
    public ASTExpr A, B;
    public SumExpr(ASTExpr a, ASTExpr b) =>
      (A, B) = (a, b);

    public override string ToString() => $"({A.ToString()}) + ({B.ToString()})";
}

public override ASTExpr Visit(SumExpr e)
    {
        return new SumExpr(
          Visit(e.A),
          Visit(e.B));
    }

eA是ASTExpr,但是沒有可以為ASTExpr調用的方法Visit。

對象類型是在編譯期間而不是在運行時定義的。

添加以下方法

public override ASTExpr Visit(ASTExpr e)
    {
        if (e as SumExpr != null)
            return Visit(e as SumExpr);

        if (e as ProductExpr != null)
            return Visit(e as ProductExpr);

        if (e as ConstantExpr != null)
            return Visit(e as ConstantExpr);

        if (e as SymbolExpr != null)
            return Visit(e as SymbolExpr);

        throw new ArgumentException();
    }

在代碼的此部分中,您將調用ASTVisitor<ASTExpr>.Visit使用無效的參數(eA)進行訪問,其位置與預期的(e)相同。

Visit方法需要這些中的一個(的目的SumExpr , ProductExpr, ConstantExpr, SymbolExpr )和要傳遞eAASTExpr

public override ASTExpr Visit(SumExpr e){
    return new SumExpr(
      Visit(e.A),     // You are passing ASTExpr where as SumExpr is expected
      Visit(e.B));    // You are passing ASTExpr where as SumExpr is expected
  }

這肯定會改變您的邏輯,您將必須進行處理。

希望這可以幫助

我建議對@Sergey Prosin的回答稍作改進。 使用as可以正常工作,但速度較慢,因為as每次使用都會先檢查類型是否匹配。 相反,您可以將as表達式結果分配給變量,然后使用它,也可以使用新is模式匹配語法:

public override ASTExpr Visit(ASTExpr e)
{
    if (e is SumExpr sum)
        return Visit(sum);

    if (e is ProductExpr product)
        return Visit(product);

    if (e is ConstantExpr constant)
        return Visit(constant);

    if (e is SymbolExpr symbol)
        return Visit(symbol);

    throw new ArgumentException();
}

甚至更酷switch模式匹配:

public override ASTExpr Visit(ASTExpr e)
{
    switch (e)
    {
        case SumExpr sum:
           return Visit(sum); 
        case ProductExpr product:
           return Visit(product);
        case ConstantExpr constant:
           return Visit(constant);
        case SymbolExpr symbol:
           return Visit(symbol);
        default:
           throw new ArgumentException();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM