C# 通用接口和协变性——与无效卡斯特例外作斗争

C# 通用接口和协变性——与无效卡斯特例外作斗争,c#,generics,covariance,C#,Generics,Covariance,这可能是一个经典的协方差/反方差问题,它看起来应该有效,但我可能错过了一个技巧。 我试图从工厂方法返回派生度较低的类型,但我发现无法将更专业化的具体实例转换为派生度较低的基类型 public class AnimalSettings { ... } public class CatSettings : AnimalSettings { ... } public interface IAnimalService<TSettings> { ... } public abstrac

这可能是一个经典的协方差/反方差问题,它看起来应该有效,但我可能错过了一个技巧。 我试图从工厂方法返回派生度较低的类型,但我发现无法将更专业化的具体实例转换为派生度较低的基类型

public class AnimalSettings { ... }

public class CatSettings : AnimalSettings { ... }


public interface IAnimalService<TSettings> { ... }

public abstract AnimalService<TSettings> : IAnimalService<TSettings> where TSettings : AnimalSettings { ... }


public class CatService : AnimalService<CatSettings> { ... }
这可以很好地编译,但在运行时,我的代码在尝试转换返回IAnimalService new CatService时失败;,带着一个无效的例外

我应该如何将派生度较高的类型转换为派生度较低的类型,以便调用者可以使用该接口基类型调用功能


将强制转换更改为IAnimalservice new CatService确实有效,但其目的是让调用者接收IAnimalservice,以便它可以处理任何种类的动物。换句话说,调用者不应使用任何更专门的类型。我应该在某个地方将输入或输出指定为通用定义的一部分吗?

通过给出一个完整的示例,这将更容易提供帮助-

这就是答案。正如Sweeper已经提到的,您需要在接口处添加out参数以使其工作

using System;
                    
public class Program
{
    public static void Main()
    {
        var catService = new CatService(new CatSettings());
        var genericService = (IAnimalService<AnimalSettings>)catService;
        
        genericService.DoAnimalBehavior();
    }
}

public abstract class AnimalSettings
{
    public abstract void DoAnimalBehavior();
}

public class CatSettings : AnimalSettings
{
    public override void DoAnimalBehavior()
    {
        Console.WriteLine("Meeoh");
    }
}

public interface IAnimalService<out TSettings>
{
    void DoAnimalBehavior();
}

public abstract class AnimalService<TSettings> : IAnimalService<TSettings> where TSettings : AnimalSettings
{
    private readonly TSettings _settings;
    
    public AnimalService(TSettings settings)
    {
        _settings = settings;
    }
    
    public void DoAnimalBehavior()
    {
        _settings.DoAnimalBehavior();
    }
}


public class CatService : AnimalService<CatSettings>
{
    private readonly CatSettings _catSettings;
    
    public CatService(CatSettings catSettings)
        : base(catSettings)
    {
        _catSettings = catSettings;
    }
}
它应该是IAnimalService,但取决于您在IAnimalService中使用的方法,强制转换成功可能没有意义,在这种情况下,当您尝试添加时,将出现编译器错误。
var service = MyServiceFactory.GetAnimalService(AnimalType.Cat);
service.DoAnimalBehavior();
using System;
                    
public class Program
{
    public static void Main()
    {
        var catService = new CatService(new CatSettings());
        var genericService = (IAnimalService<AnimalSettings>)catService;
        
        genericService.DoAnimalBehavior();
    }
}

public abstract class AnimalSettings
{
    public abstract void DoAnimalBehavior();
}

public class CatSettings : AnimalSettings
{
    public override void DoAnimalBehavior()
    {
        Console.WriteLine("Meeoh");
    }
}

public interface IAnimalService<out TSettings>
{
    void DoAnimalBehavior();
}

public abstract class AnimalService<TSettings> : IAnimalService<TSettings> where TSettings : AnimalSettings
{
    private readonly TSettings _settings;
    
    public AnimalService(TSettings settings)
    {
        _settings = settings;
    }
    
    public void DoAnimalBehavior()
    {
        _settings.DoAnimalBehavior();
    }
}


public class CatService : AnimalService<CatSettings>
{
    private readonly CatSettings _catSettings;
    
    public CatService(CatSettings catSettings)
        : base(catSettings)
    {
        _catSettings = catSettings;
    }
}