[英]C# No accessible extension method for override with specific type
如果已經問過了,請原諒我。 我搜索了它,但找不到任何東西。
似乎編譯器對此代碼感到困惑
public abstract class C1
{
public int c1Prop;
}
public class C2 : C1
{
public int c2Prop;
}
public abstract class P1
{
public abstract void Run<T>(T c) where T : C1;
}
public class P2 : P1
{
public override void Run<C2>(C2 c)
{
c.c1Prop = 1; //Is recognized
c.c2Prop = 2; //Is NOT recognized and is an error
}
}
我不明白為什么這在功能級別上不起作用。 由於C2擴展了C1,因此它不會違反where檢查,但是在重寫方法中仍無法識別C2類型。
在某些背景下,我在Unity ScriptableObject中使用了類似的模式,該模式不適用於通用類,因此無法將通用類型上移到類級別。 雖然將它移到那里似乎可以解決問題。
我想出的另一種可能的解決方法是一起擺脫通用方法,而支持轉換。 但是,這似乎不像泛型那樣具有表現力。 而且在整個Run方法中的多個地方強制轉換c會很煩人。
當您說void Run<C2>(C2 c)
您說的是C2
是泛型類型 ,而不是具體類型C2
。 為了更清楚一點,將C2
更改為T
:
public override void Run<T>(T c)
{
c.c1Prop = 1; //Is recognized
c.c2Prop = 2; //Is NOT recognized and is an error
}
您可以訪問c1Prop
的原因是類型約束where T : C1
在層次結構中較早。
一種解決方法是使P1
本身具有通用性:
public abstract class P1<T> where T : C1
{
public abstract void Run(T c);
}
這使得P2
看起來像這樣:
public class P2 : P1<C2>
{
public override void Run(C2 c)
{
c.c1Prop = 1;
c.c2Prop = 2;
}
}
造成混亂的最初原因是在Run
覆蓋范圍內, C2
是類型參數 - 不是稱為C2
的類。 通過在覆蓋方法的聲明中將其保留為T
可以使這一點很清楚:
public class P2 : P1
{
// Changed type parameter name from C2 to T for clarity
public override void Run<T>(T c)
{
c.c1Prop = 1;
c.c2Prop = 2;
}
}
那是絕對等效的代碼,但是更清楚了發生了什么。
現在T
受到where T : C1
約束,這就是c.c1Prop
工作方式-但c
不會是C2
是完全可行的 。 例如,我可以寫:
class OtherC1 : C1 {}
P2 p2 = new P2();
p2.Run(new OtherC1());
顯然,這不能與您當前的代碼一起使用c2Prop
中沒有OtherC1
。
聽起來您可能希望P1
是通用的,而不是Run
方法。 你可以有:
public abstract class P1<T> where T : C1
{
public abstract void Run(T c);
}
public class P2 : P1<C2>
{
public override void Run(C2 c)
{
c.c1Prop = 1; //Is recognized
c.c2Prop = 2; //Is NOT recognized and is an error
}
}
然后將進行編譯,並且所有代碼都將知道您只能向P2.Run
提供一個C2
(或更多派生類)。 因此,我們先前使用OtherC1
示例將不再編譯(這是我們想要的)。
您的方法簽名指出該方法應該是通用的,並且不能僅對某些具體類型覆蓋它,您可以執行以下操作:
public class P2 : P1
{
public override void Run<T>(T c)
{
c.c1Prop = 1; //Is recognized since you have where T : C1 clause
var c2 = c as C2;
if (c2 != null)
{
c2.c2Prop = 2;
}
}
}
雖然我支持@DavidG的方法,但是如果您不想在類上使用泛型聲明,則可以使用此方法
public interface IC1
{
int prop1 { get; set; }
}
public interface IC2
{
int prop2 { get; set; }
}
public abstract class C1 : IC1
{
#region Implementation of IC1
public int prop1 { get; set; }
#endregion
}
public class C2 : C1, IC2
{
#region Implementation of IC2
public int prop2 { get; set; }
#endregion
}
public abstract class P1
{
public abstract void Run<T>(T c) where T : IC1, IC2;
}
public class P2 : P1
{
public override void Run<T>(T c)
{
c.prop1 = 1;
c.prop2 = 2;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.