[英]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);
}
}
SumExpr
, ProductExpr
, ConstantExpr
, SymbolExpr
實現:
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()})";
}
SumExpr
, ProductExpr
, ConstantExpr
, SymbolExpr
繼承自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
)和要傳遞eA
是ASTExpr
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.