[英]How to point to underlying class of <T> in generic factory
吃了些蔬菜:
public interface IVegetable
{
}
public class Potato : IVegetable
{
}
public class Onion : IVegetable
{
}
我们将专注于洋葱并对其进行处理:我有一个通用蔬菜处理器的通用接口和一个特定于洋葱的接口:
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<Onion>
{
void MakeCry(Onion onion);
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(Onion onion)
{
return "Purple";
}
public void MakeCry(Onion onion)
{
Console.WriteLine($"{onion} made you cry!");
}
}
以及通用工厂:
interface IVegetableProcessorFactory
{
IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
{
object processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return (IVegetableProcessor<T>)processor; //this will fail later
}
}
最后这不起作用:
static void Main(string[] args)
{
var onion = new Onion() as IVegetable;
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
错误是:
System.InvalidCastException: 'Unable to cast object of type 'OnionProcessor' to type 'IVegetableProcessor`1[Vegetables.Program+IVegetable]'.'
如何让它理解 IVegetable 的底层类并将处理器转换为它的相应类型?
您的输入已经是逆变的,但是通过将您的 Onion 实例转换为IVegetable
,它不再能够在您的工厂中被转换回IVetetableProcessor<T>
,因为此时您需要IVetetableProcessor<Onion>
,但是您拥有的是IVegetableProcessor<IVegetable>
,并且您的界面不是协变的。
通过简单地将new Onion
的初始转换删除到IVegetable
,您的代码将按原样工作:
static void Main(string[] args)
{
var onion = new Onion();
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
public interface IVegetable { }
public class Potato : IVegetable { }
public class Onion : IVegetable { }
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<Onion>
{
void MakeCry();
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(Onion vegetable)
{
return "Purple";
}
public void MakeCry()
{
Console.WriteLine("You cry now!");
}
}
interface IVegetableProcessorFactory
{
IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
{
var processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return (IVegetableProcessor<T>)processor;
}
}
你必须首先投射的事实是你暗示你的作品中有什么东西被破坏了。 正如 Selvin 在评论中提到的,实现IVegetableProcessor<Onion>
与实现IVegetableProcessor<IVegetable>
。
您的处理器接口应该实现IVegetableProcessor<IVegetable>
并采用 IVegetable 实例,允许输入参数的逆变:
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<IVegetable>
{
void MakeCry();
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(IVegetable vegetable)
{
return "Purple";
}
public void MakeCry()
{
Console.WriteLine("You cry now!");
}
}
interface IVegetableProcessorFactory
{
IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable);
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable)
{
var processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return processor;
}
}
通过以下方式运行时,这会正确输出“Purple”:
static void Main(string[] args)
{
var onion = new Onion();
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.