通用类与继承

huangapple go评论95阅读模式
英文:

Generic classes with Inheritance

问题

以下是翻译好的内容:

我有下面的方法,它返回一个泛型类的实例。这是一个简单的工厂类。我有一个泛型类叫做FileReader<T>,它可以读取Chase、Products、customers、suppliers等的管道分隔的文本文件,并将数据填充到相应的BusinessObjects中。我试图实现的是一个泛型文件读取器。所有这些业务对象都派生自BusinessBase类。

  1. public override FileReaderGeneric&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig)
  2. {
  3. return new FileReaderGeneric&lt;Chase&gt;(jobConfig);
  4. }

BusinessBase不是一个泛型类。BusinessBase只有验证函数。然而,上面的代码给我一个错误
无法隐式将类型<BusinessLayer.Chase>转换为<BusinessLayer.BusinessBase>

根据评论进行了编辑
看起来我的泛型理解不正确

英文:

I am having the below method that returns an instance of a Generic Class. This is a simple factory class. I have a Generic class called FileReader<T> which reads pipe-delimited txt file of Chase,Products, customers, suppliers etc and populate the data into respective BusinessObjects. I am trying to achieve is a Generic file reader. All these business objects derive from BusinessBase class.

  1. public override FileReaderGeneric&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig)
  2. {
  3. return new FileReaderGeneric&lt;Chase&gt;(jobConfig);
  4. }

The BusinessBase is not a generic class. The BusinessBase only has validation functions. However, the above code is giving me an error
Cannot implicitly convert type <BusinessLayer.Chase> to <BusinessLayer.BusinessBase>

Edited based on the comments
Looks like my understanding on Generics is not correct

答案1

得分: 1

With C# generics, you cannot cast an instance of a generic class to another. For instance:

  1. class A {
  2. }
  3. class B : A {
  4. }
  5. class Foo<T> where T : A {
  6. }
  7. Foo<A> fooA = new Foo<A>();
  8. Foo<B> fooB = new Foo<B>();

Even though A is the supertype of B, you cannot then say:

  1. fooA = (Foo<A>)fooB;

The language does not allow it: the types Foo<A> and Foo<B> are completely unrelated; only their generic parameters are related.

This code:

  1. using System;
  2. class A
  3. {
  4. }
  5. class B : A
  6. {
  7. }
  8. class Foo<T>
  9. where T : A
  10. {
  11. }
  12. public class Program
  13. {
  14. public static void Main()
  15. {
  16. Foo<A> fooA = new Foo<A>();
  17. Foo<B> fooB = new Foo<B>();
  18. Foo<A> xxxx = (Foo<A>)fooB;
  19. }
  20. }

will give you a compilation error Compilation error (line 22, col 17): Cannot convert type 'Foo<B>' to 'Foo<A>' on the assignment statement:

  1. Foo<A> xxxx = (Foo<A>)fooB;

Updating this to offer possible solutions

Since it sounds like the BusinessBase instance that you are instantiating are not exposed to the consumers of the instantiated instances of FileReaderGeneric<T>, there are a couple of things you can do.

Assuming that your generic class looks something like this:

  1. class FileReaderGeneric<T> where T : BusinessBase
  2. {
  3. // ...
  4. }

you can . . .

Use Dependency Injection

  1. class FileReader
  2. {
  3. private BusinessBase bb
  4. private FileReader(BusinessBase bb, ImportJobConfig jobConfig)
  5. {
  6. this.bb = bb;
  7. }
  8. public static FileReader CreateFileReader(BusinessBase bb, ImportJobConfig jobConfig)
  9. {
  10. return new FileReader(bb, jobConfig);
  11. }
  12. }

Use An Abstract Base Class

  1. public abstract class AbstractFileReader
  2. {
  3. // ...
  4. }
  5. class FileReader<T> : AbstractFileReader where T : BusinessBase
  6. {
  7. private FileReader(ImportJobConfig jobConfig)
  8. {
  9. }
  10. public static AbstractFileReader CreateFileReader(ImportJobConfig jobConfig)
  11. {
  12. return new FileReader<Chase>(jobConfig);
  13. }
  14. }
英文:

With C# generics, you cannot cast an instance of a generic class to another. For instance, given

  1. class A {
  2. }
  3. class B : A {
  4. }
  5. class Foo&lt;T&gt; where T:A {
  6. }
  7. Foo&lt;A&gt; fooA = new Foo&lt;A&gt;();
  8. Foo&lt;B&gt; fooB = new Foo&lt;B&gt;();

Even though A is the supertype of B, you cannot then say

  1. fooA = (Foo&lt;A&gt;)fooB;

Even though A is the supertype of B. The language does not allow it: the types Foo&lt;A&gt; and Foo&lt;B&gt; are completely unrelated: only their generic parameters are related.

This code:

  1. using System;
  2. class A
  3. {
  4. }
  5. class B : A
  6. {
  7. }
  8. class Foo&lt;T&gt;
  9. where T : A
  10. {
  11. }
  12. public class Program
  13. {
  14. public static void Main()
  15. {
  16. Foo&lt;A&gt; fooA = new Foo&lt;A&gt;();
  17. Foo&lt;B&gt; fooB = new Foo&lt;B&gt;();
  18. Foo&lt;A&gt; xxxx = (Foo&lt;A&gt;)fooB;
  19. }
  20. }

will give you a compilation error Compilation error (line 22, col 17): Cannot convert type &#39;Foo&lt;B&gt;&#39; to &#39;Foo&lt;A&gt;&#39;

on the assignment statement

  1. Foo&lt;A&gt; xxxx = (Foo&lt;A&gt;)fooB;

Updating this to offer possible solutions

Since it sounds like the BusinessBase instance that you are instantiating are not exposed to the consumers of the instantiated instances of FileReaderGeneric&lt;T&gt;, there are a couple of things you can do.

Assuming that your generic class looks something like this:

  1. class FileReaderGeneric&lt;T&gt; where T:BusinessBase
  2. {
  3. ...
  4. }

you can . . .

Use Dependency Injection

  1. class FileReader
  2. {
  3. private BusinessBase bb
  4. private FileReader( BusinessBase bb, ImportJobConfig jobConfig )
  5. {
  6. this.bb = bb;
  7. }
  8. public static FileReader CreateFileReader( BusinessBase bb , ImportJobConfig jobConfig )
  9. {
  10. return new FileReader( bb , jobConfig );
  11. }
  12. }

Use An Abstract Base Class

  1. public abstract class AbstractFileReader
  2. {
  3. . . .
  4. }
  5. class FileReader&lt;T&gt; : AbstractFileReader where T:BusinessBase
  6. {
  7. private FileReader( ImportJobConfig jobConfig )
  8. {
  9. }
  10. public static AbstractFileReader CreateFileReader( ImportJobConfig jobConfig )
  11. {
  12. return new FileReader&lt;Chase&gt;( jobConfig );
  13. }
  14. }

答案2

得分: 0

以下是翻译好的代码部分:

  1. 你可能想在这里使用一个通用方法。通过类型约束,你可以限制调用者只能使用从BusinessBase派生的类型。像这样:
  2. public override FileReaderGeneric&lt;TBusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig) where TBusinessBase: BusinessBase
  3. {
  4. return new FileReaderGeneric&lt;TBusinessBase&gt;(jobConfig);
  5. }
  6. 你需要相应地更改包含此覆盖方法的类,因为这个覆盖方法的签名已经不再与以前相同。
英文:

You likely want to use a generic method here. With type constraints, you can limit callers to using a type derived from BusinessBase. Something like this

  1. public override FileReaderGeneric&lt;TBusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig) where TBusinessBase: BusinessBase
  2. {
  3. return new FileReaderGeneric&lt;TBusinessBase&gt;(jobConfig);
  4. }

You will need to change the containing class appropriately because this overriding method no longer has the same signature it did before.

答案3

得分: 0

public class ImportJobConfig { }

public class BusinessBase { }

public class Chase : BusinessBase { }

public interface IFileReader { }

public class FileReaderGeneric : IFileReader {
public FileReaderGeneric(ImportJobConfig jc) { }
}

public override IFileReader CreateFileReader(ImportJobConfig jobConfig) {
return (IFileReader)(new FileReaderGeneric(jobConfig));
}

英文:

If you create an interface to describe a file reader, and use that interface with a covariant generic type, you can cast the types:

  1. public class ImportJobConfig { }
  2. public class BusinessBase { }
  3. public class Chase : BusinessBase { }
  4. public interface IFileReader&lt;in T&gt; { }
  5. public class FileReaderGeneric&lt;T&gt; : IFileReader&lt;T&gt; {
  6. public FileReaderGeneric(ImportJobConfig jc) { }
  7. }
  8. public override IFileReader&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig) {
  9. return (IFileReader&lt;BusinessBase&gt;)(new FileReaderGeneric&lt;Chase&gt;(jobConfig));
  10. }

huangapple
  • 本文由 发表于 2023年6月13日 04:56:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76460278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定