通用类与继承

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

Generic classes with Inheritance

问题

以下是翻译好的内容:

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

public override FileReaderGeneric&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig)
{
    return new FileReaderGeneric&lt;Chase&gt;(jobConfig);
}

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.

public override FileReaderGeneric&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig)
        {
            return new FileReaderGeneric&lt;Chase&gt;(jobConfig);
        }

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:

class A {
}

class B : A {
}

class Foo<T> where T : A {
}

Foo<A> fooA = new Foo<A>();
Foo<B> fooB = new Foo<B>();

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

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:

using System;

class A
{
}

class B : A
{
}

class Foo<T>
	where T : A
{
}

public class Program
{
	public static void Main()
	{
		Foo<A> fooA = new Foo<A>();
		Foo<B> fooB = new Foo<B>();
		Foo<A> xxxx = (Foo<A>)fooB;
	}
}

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

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:

class FileReaderGeneric<T> where T : BusinessBase
{
  // ...
}

you can . . .

Use Dependency Injection

class FileReader
{
  private BusinessBase bb
  private FileReader(BusinessBase bb, ImportJobConfig jobConfig)
  {
    this.bb = bb;
  }

  public static FileReader CreateFileReader(BusinessBase bb, ImportJobConfig jobConfig)
  {
    return new FileReader(bb, jobConfig);
  }
}

Use An Abstract Base Class

public abstract class AbstractFileReader
{
  // ...
}

class FileReader<T> : AbstractFileReader where T : BusinessBase
{
  private FileReader(ImportJobConfig jobConfig)
  {
  }

  public static AbstractFileReader CreateFileReader(ImportJobConfig jobConfig)
  {
    return new FileReader<Chase>(jobConfig);
  }
}
英文:

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

class A {
}

class B : A {
}

class Foo&lt;T&gt; where T:A {
}

Foo&lt;A&gt; fooA = new Foo&lt;A&gt;();
Foo&lt;B&gt; fooB = new Foo&lt;B&gt;();

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

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:

using System;

class A
{
}

class B : A
{
}

class Foo&lt;T&gt;
	where T : A
{
}

public class Program
{
	public static void Main()
	{
		Foo&lt;A&gt; fooA = new Foo&lt;A&gt;();
		Foo&lt;B&gt; fooB = new Foo&lt;B&gt;();
		Foo&lt;A&gt; xxxx = (Foo&lt;A&gt;)fooB;
	}
}

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

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:

class FileReaderGeneric&lt;T&gt; where T:BusinessBase
{
  ...
}

you can . . .

Use Dependency Injection

class FileReader
{
  private BusinessBase bb
  private FileReader( BusinessBase bb, ImportJobConfig jobConfig )
  {
    this.bb = bb;
  }

  public static FileReader CreateFileReader( BusinessBase bb , ImportJobConfig jobConfig )
  {
    return new FileReader( bb , jobConfig );
  }

}

Use An Abstract Base Class

public abstract class AbstractFileReader
{
  . . .
}

class FileReader&lt;T&gt; : AbstractFileReader where T:BusinessBase
{
  private FileReader( ImportJobConfig jobConfig )
  {
  }

  public static AbstractFileReader CreateFileReader( ImportJobConfig jobConfig )
  {
    return new FileReader&lt;Chase&gt;( jobConfig );
  }

}

答案2

得分: 0

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

你可能想在这里使用一个通用方法。通过类型约束,你可以限制调用者只能使用从BusinessBase派生的类型。像这样:

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

你需要相应地更改包含此覆盖方法的类,因为这个覆盖方法的签名已经不再与以前相同。
英文:

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

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

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:

public class ImportJobConfig { }

public class BusinessBase { }

public class Chase : BusinessBase { }

public interface IFileReader&lt;in T&gt; { }

public class FileReaderGeneric&lt;T&gt; : IFileReader&lt;T&gt; {
    public FileReaderGeneric(ImportJobConfig jc) { }
}

public override IFileReader&lt;BusinessBase&gt; CreateFileReader(ImportJobConfig jobConfig) {
    return (IFileReader&lt;BusinessBase&gt;)(new FileReaderGeneric&lt;Chase&gt;(jobConfig));
}

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:

确定