[英]C#: Assign child class instance to interface implemented by abstract class
public interface IParser<T> where T: new()
{
IList<T> Parse();
}
Above interface is implemented by following abstract class 上面的接口是通过以下抽象类实现的
public abstract class BaseParser<T>: IParser<T> where T : new()
{
protected abstract string Sql { get;}
public List<T> Parse()
{
// do parsing
Console.WriteLine(Sql);
}
}
Following are two concrete implementation of above abstract class 以下是上面抽象类的两个具体实现
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";
}
}
}
Usage: 用法:
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();
}
}
I want to create instance of EmailParser
or UrlParser
base on generic type provided in Program.Main
method and assign it to interface implemented by BaseParser
(abstract class). 我想基于Program.Main
方法中提供的泛型类型创建EmailParser
或UrlParser
实例,并将其分配给BaseParser
实现的BaseParser
(抽象类)。 How can I do this? 我怎样才能做到这一点? I know i can solve this problem by modifying Program.Parse<T>
as following 我知道我可以通过修改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();
}
However I want to know why I can't assign child class instance to interface implemented by abstract class?? 但是我想知道为什么我不能将子类实例分配给抽象类实现的接口?
I can't understand why following line does not work 我无法理解为什么以下行不起作用
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser(): new EmailParser();
and why this line work 为什么这条线工作
IParser<T> parser = typeof(T) == typeof(Url) ? new UrlParser() as BaseParser<T> : new EmailParser() as BaseParser<T>;
As per @nawfal answer this line also should not work because BaseParser and BaseParser are different types. 根据@nawfal的回答,这一行也不应该起作用,因为BaseParser和BaseParser是不同的类型。 Does there exists implicit case for IParser from BaseParser? BaseParser中是否存在IParser的隐含案例?
I believe the issue is that the compiler doesn't consider the type to which you are assigning the result of the ?: conditional when parsing the conditional. 我认为问题在于编译器在解析条件时不考虑将?:conditional的结果分配给的类型。 Rather, the ?: is parsed in isolation, so the compiler can't figure out which type to use. 相反,?:是独立解析的,因此编译器无法确定要使用的类型。
Edit: From section 7.14 of the C# 5.0 specification: 编辑:从C#5.0规范的第7.14节:
The second and third operands, x and y, of the ?: operator control the type of the conditional expression. ?:运算符的第二个和第三个操作数x和y控制条件表达式的类型。 If x has type X and y has type Y then: 如果x的类型为X且y的类型为Y,则:
If an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression. 如果从X到Y存在隐式转换(第6.1节),而不是从Y到X,则Y是条件表达式的类型。
If an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression. 如果从Y到X存在隐式转换(第6.1节),而不是从X到Y,则X是条件表达式的类型。
Otherwise, no expression type can be determined, and a compile-time error occurs. 否则,无法确定表达式类型,并发生编译时错误。
Because there is no implicit conversion between UrlParser
and EmailParser
. 因为UrlParser
和EmailParser
之间没有隐式转换。 They both go back to BaseParser<Url>
and BaseParser<Email>
(or IParser<Url>
and IParser<Email>
) respectively, both of which are different types as far as compiler is concerned. 它们分别返回BaseParser<Url>
和BaseParser<Email>
(或IParser<Url>
和IParser<Email>
),就编译器而言,它们都是不同的类型。
I would keep a dictionary to hold a map of type information and then use reflection. 我会保留一本字典来保存类型信息的地图,然后使用反射。 Something like (not tested): 像(未经测试)的东西:
static Dictionary<string, Type> typeInfos = new Dictionary<string, Type>
{
{ "url", typeof(Url) },
{ "email", typeof(Email) },
// and so on
};
And you do, 你也是,
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();
}
}
Use expression trees and/or cache things to make things faster. 使用表达式树和/或缓存事物来加快速度。
Update: No, BaseParser<T>
and BaseParser<T>
are the exact same thing. 更新:不, BaseParser<T>
和BaseParser<T>
完全相同。 T
can only have one value at a time in your generic method. 在泛型方法中, T
一次只能有一个值。 The real question is how can you cast new UrlParser() as BaseParser<T>
. 真正的问题是如何将new UrlParser() as BaseParser<T>
。 In a generic context it is possible to cast anything to anything using as
C# rules are bit liberal there (I dont know the which part exactly in spec). 在一般情况下,可以用投什么东西as
C#规则是位自由主义那里(我不知道这部分正好符合规格)。
You can use a dynamic dispatch: 您可以使用动态调度:
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)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.