簡體   English   中英

類型參數必須是逆變有效的

[英]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.

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