public interface IParser<T> where T: new()
{
IList<T> Parse();
}
上面的接口是通过以下抽象类
实现的public abstract class BaseParser<T>: IParser<T> where T : new()
{
protected abstract string Sql { get;}
public List<T> Parse()
{
// do parsing
Console.WriteLine(Sql);
}
}
以下是上面抽象类的两个具体实现
public class EMailParser: BaseParser<Email>
{
protected override string Sql
{
get
{
return @"SELECT * FROM emails";
}
}
}
public class UrlParser : BaseParser<Url>
{
protected override string Sql
{
get
{
return @"SELECT * From Url";
}
}
}
用法:
class Program
{
static void Main(string[] args)
{
if(args[1] == "url")
Parser<Url>();
else
Parser<Email>();
}
static void Parse<T>()
{
// Create instance based on typof T and then assign to implementaion
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser(): new EmailParser();
parser.Parse();
}
}
我想基于EmailParser
方法中提供的泛型类型创建UrlParser
或Program.Main
的实例,并将其分配给BaseParser
实现的接口(抽象类)。我怎样才能做到这一点?我知道我可以通过将Program.Parse<T>
修改为以下
static void Parse<T>() where T: new()
{
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser() as BaseParser<T> : new EmailParser() as BaseParser<T>;
parser.Parse();
}
但是我想知道为什么我不能将子类实例分配给抽象类实现的接口?
我无法理解为什么以下行不起作用
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser(): new EmailParser();
为什么这条线工作
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser() as BaseParser<T> : new EmailParser() as BaseParser<T>;
根据@nawfal的回答,这一行也不应该起作用,因为BaseParser和BaseParser是不同的类型。是否存在来自BaseParser的IParser的隐含案例?
答案 0 :(得分:4)
我认为问题在于编译器不考虑您为其分配结果的类型 ? 解析条件时有条件。相反,?:是独立解析的,因此编译器无法确定要使用的类型。
编辑:来自C#5.0规范的第7.14节:
?:运算符的第二个和第三个操作数x和y控制 条件表达式的类型。如果x具有类型X并且y具有类型Y. 然后:
如果从X到Y存在隐式转换(第6.1节),而不是从Y到X,则Y是条件表达式的类型。
如果从Y到X存在隐式转换(第6.1节),但是 不是从X到Y,那么X是条件表达式的类型。
否则,无法确定表达式类型和编译时间 发生错误。
答案 1 :(得分:2)
因为UrlParser
和EmailParser
之间没有隐式转换。它们分别返回BaseParser<Url>
和BaseParser<Email>
(或IParser<Url>
和IParser<Email>
),就编译器而言,它们都是不同的类型。
我会保留一本字典来保存类型信息的地图,然后使用反射。像(未经测试)的东西:
static Dictionary<string, Type> typeInfos = new Dictionary<string, Type>
{
{ "url", typeof(Url) },
{ "email", typeof(Email) },
// and so on
};
而你这样做,
class Program
{
static void Main(string[] args)
{
Parse(args[1]);
}
static void Parse(string type)
{
var parserType = typeof(BaseParser<>)
.Assembly // or whatever the assembly is
.GetTypes()
.First(t => t.BaseType?.GetGenericArguments().FirstOrDefault() == typeInfos[type]);
dynamic parser = Activator.CreateInstance(parserType);
parser.Parse();
}
}
使用表达式树和/或缓存内容来加快速度。
更新:不,BaseParser<T>
和BaseParser<T>
完全相同。 T
在泛型方法中一次只能有一个值。真正的问题是如何投射new UrlParser() as BaseParser<T>
。在通用上下文中,可以使用as
将任何内容转换为任何内容.C#规则在那里有点自由(我不知道哪个部分完全符合规范)。
答案 2 :(得分:1)
您可以使用动态调度:
static IParser<Url> CreateParser(Url uri)
{
return new UrlPaqrser<Url>();
}
static IParser<Email> CreateParser(Email mail)
{
return new EmailPaqrser<Email>();
}
static void Main(string[] args)
{
dynamic t = new Url();
var parser = CreateParser(t); // invokes CreateParser(Url uri)
t = new Email();
parser = CreateParser(t); // invokes CreateParser(Email email)
}