2017-06-16 27 views
2

这应该很简单,但我一直遇到这个问题。我有一个通用类Csvs<T>,通过名为Dockets的属性返回List<T>类型的方法。 (该方法读取CSV文件并返回该CSV文件中记录的列表,T是该CSV文件的类型,该文件在一系列模型中定义,其中包含标题行作为属性)如何在c#中存储返回的列表<T>?

在我的调用类(我不能使通用),我有一个包含我在T.

使用类的名称
switch (_userInput.CsvType) 
      { 
       case CsvType.Type1: 
        var csvType1 = new Csvs<Type1>(_userInput); 
        _dockets = csvType1.Dockets;       
        break; 
       case CsvType.Type2: 
        var csvType2 = new Csvs<Type2>(_userInput); 
        _dockets = csvType2.Dockets;       
        break; 
       case CsvType.Type3: 
        var csvType3 = new Csvs<Type3>(_userInput); 
        _dockets = csvType3.Dockets;       
        break; 
       // more cases here [...] 
       default: 
        throw new ArgumentOutOfRangeException(); 
      } 

(这将是很好,如果我能找到一个基于一个enum switch语句比使用这个开关更好的方法,但它现在可行。)

什么不起作用,或者我不知道该怎么办,如何申报_dockets?由于T可以是任何类型。我试着提取接口ICsvs,并有类继承它,然后声明

var _dockets = new List<ICsvs>; 

但是,这将引发一个错误,我不能隐式转换的List<Type1>List<ICsvs>

而且我不能将该列表投射到类型List<ICsvs>。 (然后我得到了一个异常)

无法通过引用转换型“System.Collections.Generic.List”转换为“System.Collections.Generic.List”,装箱转换,取消装箱转换,包装转换,或空类型转换

如果我使用抽象类,则会发生同样的情况。

那么,如何将返回的List存储在调用类中?我如何声明可以容纳任何类型的字段或属性?

+0

当您在编译时知道类型时,泛型始终工作得最好。如果你只知道他们在运行时键入,你可能*不想要泛型。 – Jamiec

+0

@Jamiec,通用类的作品...我只是不知道如何存储返回类型? – ToshiBoy

+1

正是我的观点。您可以使用开关来实例化正确的泛型类,但不能以任何有意义的方式使用它,因为您不知道它们的类型。 – Jamiec

回答

0

我认为我以后的事情,即存储以后使用的返回值,dynamic是最好的答案(谢谢@Rahul)。我可以在后面担心类型。感谢大家的帮助。

dynamic _dockets; 

然后通过返回切换大小写。

1

实现这一目标的最简单的方法是让所有类型的实施ICsv,像这样:

interface ICsv { } 

class CsvType1 : ICsv { } 

class CsvType2 : ICsv { } 

class Csvs<TCsvModel> 
    where TCsvModel: ICsv 
{ 
    public Csvs(IList<TCsvModel> csvModel) 
    { 
     this.Dockets = csvModel; 
    } 

    public IList<TCsvModel> Dockets { get; private set;} 
} 

所以,你可以使用此类似:

IEnumerable<ICvs> dockets; 

var cvsType1 = new Csvs<CsvType1>(_input); 
dockets = cvsType1.Dockets 

var cvsType2 = new Csvs<CsvType2>(_input); 
dockets = cvsType2.Dockets 
+0

很好。谢谢。 – ToshiBoy

+0

这与OP代码无效的原因不一样。 http://rextester.com/PRWX41261 – Jamiec

+0

不,关闭:它抛出'参数1:无法从'System.Collections.Generic.List '转换为'System.Collections.Generic.IEnumerable '' – ToshiBoy

0

最有意义/多态性的事情你可以做的就是让Dockets属性返回一个描述你对它们做什么的接口。根据您的要求,这可能也可能不可行 - 但您没有其他选择。正如我所评论的,当您在编译时知道类型时,泛型真的只会运行良好。

作为一个例子。接口

public interface IDockets 
{ 
    void DoSomethingWithRecords(); 
} 

一般实现它会从你的Csvs

public class Dockets<T> : IDockets 
{ 
    private IEnumerable<T> dockets; 
    public Dockets(IEnumerable<T> dockets) 
    { 
     this.dockets = dockets; 
    } 
    public void DoSomethingWithRecords() 
    { 
     foreach(var docket in dockets) 
      Console.WriteLine(docket); // do whatever 
    } 
} 

返回这个类,然后从你的CsvsDockets财产

public class Csvs<T> 
{ 
    private List<T> parsedDockets; // assume you have something like this: 
    public IDockets Dockets{ get { return new Dockets(parsedDockets); } } 
} 

而且你调用代码返回

IDockets dockets = null; 
switch (_userInput.CsvType) 
{ 
    case CsvType.Type1: 
     var csvType1 = new Csvs<Type1>(_userInput); 
     dockets = csvType1.Dockets;       
     break; 
    // Snip // 
} 
dockets.DoSomethingWithRecords(); 
+0

IEnumerable的问题是我需要添加CSV中的值,所以List会更好。 – ToshiBoy

+0

@ToshiBoy无论列表还是枚举都没有区别。无论如何,你大概会把它们加到'Csvs'的列表中 - 当你将它们吐出到'Dockets'时,你可能不需要再添加任何东西。 – Jamiec

相关问题