簡體   English   中英

無法將泛型類型的對象強制轉換為通用接口C#

[英]Unable to cast object of generic type to generic interface C#

我有兩個接口:

public interface IDbModel {}
public interface IDmModel {}

和派生自這的類:

public class DbModel : IDbModel {}
public class DmModel : IDmModel {}
public class Middle { }

另外我有兩個限制接口:

public interface IRule { }
public interface IRule<in TInput, out TOutput> : IRule
    where TInput : IDmModel
    where TOutput : IDbModel
{
    TOutput Apply(TInput elem);
}

從這個接口派生出一個抽象類:

public abstract class Rule<TDmModel, TMiddle, TDb> : IRule<TDmModel, TDb>
    where TDmModel : IDmModel
    where TDb : IDbModel
{
    private readonly Func<TDmModel, TMiddle> _rule;
    protected Rule(Func<TDmModel, TMiddle> rule) { _rule = rule; }
    protected abstract TDb Apply(TMiddle transformedMessage);
    public TDb Apply(TDmModel elem) { ... }
}

在此之后,我創建了兩個派生自此抽象類的類:

public class RuleA : Rule<DmModel, Middle, DbModel>
{
    public RuleA(Func<DmModel, Middle> rule) : base(rule) {}
    protected override DbMode Apply(Middle transformedMessage) { ... }
}

public class RuleB : RuleA
{
    public RuleB() : base((dm) => new Middle()) {}
}

RuleB:RuleA:Rule <DmModel,Middle,DbModel>:IRule <IDmModel,IDbModel>:IRule

當我嘗試將RuleB對象RuleBIRule<IDmModel, IDbModel>出現未處理的異常

無法將類型為'ParsreCombinators.RuleB'的對象轉換為'ParsreCombinators.IRule`2 [ParsreCombinators.IDmModel,ParsreCombinators.IDbModel]'。

var ruleB = (IRule<IDmModel, IDbModel>)new RuleB(); // Exception 
IDbModel dbModel = ruleB.Apply(new DmModel());

有什么不對這個

為了減少混亂,我簡化了它:

編輯:

在我理解了答案之后,問題是什么,並使示例不那么混亂我簡化它:

public interface IDbModel {}
public interface IDmModel {}

public class DbModel : IDbModel {}
public class DmModel : IDmModel {}

public interface IRule<in TInput, out TOutput>
    where TInput : IDmModel
    where TOutput : IDbModel
{
    TOutput Apply(TInput elem);
}

public class RuleA : IRule<DmModel, DbModel>
{
    public DbModel Apply(DmModel elem) { ... }
}

var ruleA = (IRule<IDmModel, IDbModel>)new RuleA(); // Exception

你到那里的間接程度很高......

這是問題所在:

public abstract class Rule<TDmModel, TMiddle, TDb> : IRule<TDmModel, TDb>
    where TDmModel : IDmModel
    where TDb : IDbModel

public class RuleA : Rule<DmModel, Middle, DbMode>
public class RuleB : RuleA
...
var ruleB = (IRule<IDmModel, IDbModel>)new RuleB();

RuleB實現了IRule <DmModel,DbMode>

這不能轉換為IRule <IDmModel,IDbModel>。 C#不支持這種類型的轉換。 出於同樣的原因,你不能做List<object> b = (List<object>)new List<string>(); (提供“無法將類型'System.Collections.Generic.List <string>轉換為System.Collections.Generic.List <object>。”)

這是協方差的問題。

以下是Microsoft提供的有關此主題的更多信息: https//docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

這是一個非常令人困惑的例子,但我相信問題是你正在轉換為泛型類型並給它接口,當你派生的類強制你使用DmModel和DbMode時。

也許這就是你的意思:

var ruleB = (IRule<DmModel, DbMode>)new RuleB();

編譯得很好,我用這種方式構建你的類,是重組之外的唯一選擇。

你的界面IRule<in TInput, out TOutput>既是協變的又是逆變的,這意味着你無法共同演變它。 逆變阻止了這種情況。

基本上,你的賦值var dbModel = (IRule<IDmModel, IDbModel>)new RuleB(); 斷言dbModel必須接受任何 IDmModel參數。 不幸的是,事實並非如此; 實例必須分配給DmModel由於的具體形式RuleA ,如此其它衍生物IDmModel會失敗。

暫無
暫無

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

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