简体   繁体   English

C#:将子类实例分配给抽象类实现的接口

[英]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方法中提供的泛型类型创建EmailParserUrlParser实例,并将其分配给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 . 因为UrlParserEmailParser之间没有隐式转换。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM