[英]Type parameter must be contravariantly valid
考慮一只鳥:
public interface IBird
{
}
public class Duck : IBird
{
public string DuckyProperty { get; set; } //this property is Duck specific!
}
還有一個鳥類處理器:
public interface IBirdProcessor<out T> where T : IBird
{
double GetBirdWeight(T obj); //this does not compile
}
public class DuckProcessor : IBirdProcessor<Duck>
{
public double GetBirdWeight(Duck duck)
{
return double.Parse(duck.DuckyProperty);
}
}
和一家工廠獲得鳥類處理器:
public class BirdProcessorFactory
{
public IBirdProcessor<T> GetBirdProcessor<T>(T obj) where T : IBird
{
return (IBirdProcessor<T>)new DuckProcessor();
}
}
啟動:
static void Main()
{
var bird = new Duck() { DuckyProperty = "23" } as IBird; //the cast is necessary to simulate a real world scenario
var factory = new BirdProcessorFactory();
var provider = factory.GetBirdProcessor(bird);
var weight = provider.GetBirdWeight(bird);
}
我想要一個抽象的通用鳥類工廠,但我收到以下錯誤:
The type parameter 'T' must be contravariantly valid on 'Program.IBirdProcessor<T>.GetBirdWeight(T)'. 'T' is covariant
如果我刪除“out”關鍵字,那么我會得到:
System.InvalidCastException: 'Unable to cast object of type 'DuckProcessor' to type 'IBirdProcessor`1[NotVegetables.Program+IBird]'.'
演員陣容不行!
作為一種解決方法,我可以這樣做:
public class DuckProcessor : IBirdProcessor<IBird>
{
public double GetBirdWeight(IBird bird)
{
var duck = bird as Duck;
return double.Parse(duck.DuckyProperty);
}
}
但這完全違背了 generics 的用法,我覺得 DuckProcessor 應該適用於鴨子,而不是抽象的鳥類。
我做錯了什么嗎?
C# generics 中的所有類型都必須在編譯時知道。 只有IBird
在編譯時是已知的,工廠必須返回一個IBirdProcessor<IBird>
。 由於協變不是一個選項(因為DuckProcessor.GetBirdWeight
只接受Duck
s),因此無法返回DuckProcessor
。
你可以得到你想要的行為:
public interface IBirdProcessor
{
double GetBirdWeight(IBird obj);
}
public abstract class BirdProcessorBase<T> : IBirdProcessor where T : IBird
{
public double GetBirdWeight(IBird bird) => GetBirdWeightInternal((T)bird);
protected abstract double GetBirdWeightInternal(T bird);
}
public class DuckProcessor : BirdProcessorBase<Duck>
{
protected override double GetBirdWeightInternal(Duck duck)
{
return double.Parse(duck.DuckyProperty);
}
}
public class BirdProcessorFactory
{
public IBirdProcessor GetBirdProcessor(IBird bird)
{
if (bird.GetType().IsAssignableTo(typeof(Duck)))
return new DuckProcessor();
throw new Exception($"No processor for {bird.GetType().Name}");
}
}
但是,如果您使用不匹配的類型調用從工廠返回的處理器,它會向您拋出異常。
請查看我的問題解決方案:
public interface IBird
{
}
public class Duck : IBird
{
public string DuckyProperty { get; set; } //this property is Duck specific!
}
public class Chicken : IBird
{
public string ChickenProperty { get; set; } //this property is Chicken specific!
}
public interface IBirdProcessor<Y>
where Y : IBird
{
double GetBirdWeight(Y obj);
}
public class DuckProcessor : IBirdProcessor<Duck>
{
public double GetBirdWeight(Duck duck)
{
return double.Parse(duck.DuckyProperty);
}
}
public class ChickenProcessor : IBirdProcessor<Chicken>
{
public double GetBirdWeight(Chicken chicken)
{
return double.Parse(chicken.ChickenProperty);
}
}
public class BirdProcessorFactory
{
public static IBirdProcessor<T> GetProcessor<T>(T bird)
where T : IBird
{
switch (bird){
case Chicken t1:
return (IBirdProcessor<T>)new ChickenProcessor();
case Duck t1:
return (IBirdProcessor<T>)new DuckProcessor();
default:
throw new ArgumentException();
}
}
}
為了顯示它按預期工作,我添加了額外ChickenProcessor
。
執行如下:
Duck duck = new Duck() { DuckyProperty = "23" };
Chicken chicken = new Chicken() { ChickenProperty = "25" };
var duckProvider = BirdProcessorFactory.GetProcessor(duck);
var chickenProvider = BirdProcessorFactory.GetProcessor(chicken);
duckProvider.GetBirdWeight(duck).Dump();
chickenProvider.GetBirdWeight(chicken).Dump();
結果如預期:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.