无法从Type <Type>转换为IType <IType>

时间:2019-07-29 10:21:24

标签: c# generics

我正在尝试实现通用的Excel导出。

我已经创建了两个接口IDataIDataListIData提供了将数据转换为数组的功能,IDataList提供了获取属性的相应名称的功能。

接口

public interface IData
{
    string[] GetData();
}

public interface IDataList<IData> : IList<IData>
{
    string[] GetHeader();
}

课程

public Data : IData
{
    public string col1 { get; set; }
    public string[] GetData()
    {
        return new [col1];
    }
}
public DataList : List<Data>, IDataList<Data>
{
    public string[] GetHeader()
    {
        return new ["col1"];
    }
}

尝试使用它

public void CreateDocument(IDataList<IData> dataList)
{
    // ...
    worksheet.Import(dataList.GetHeader(), RowIdx++, ColIdx, false);

    // ...
    foreach (IData data in dataList)
    {
        worksheet.Import(data.GetData(), RowIdx++, ColIdx, false);
    }
}

DataList data {get;set;} = new DataList();
// ... populate data

CreateDocument(data);

该项目将不会与错误消息一起编译: Error CS1503 Argument 1: cannot convert from 'DataList' to 'IDataList<IData>'

我想知道你能否指出正确的方向?

编辑:此问题已被标记为Why an inherited interface can't be converted to its base interface in generic context?的重复项。尽管该问题确实说明了为什么我不能以尝试的方式调用该函数,但这并不能帮助我解决问题。

我正在尝试实现为编写通用函数WriteDocument()而设计的接口。这意味着我需要访问功能GetHeader()GetData()。有人建议使用IEnumerable代替IList,但我也未能成功实现。

我所拥有的是多个对象,所有对象都必须以相同的样式写入Excel文件。这些对象具有不同的属性。借助GetData(),我可以将这些属性转换为字符串数组,可以轻松将其转储到excel文件中。 GetHeader()函数以与GetData()相同的顺序返回这些属性的名称。

我对其他方法持开放态度,但是我不确定从哪里开始。以通用的方式使用WriteDocument()函数会很酷,因此我不必为每个对象重复编写代码。

Edit2 :与其尝试使用泛型来解决这个问题,还没有一个简单得多的解决方案。重写CreateDocument-函数:

public void CreateDocument(string[] header, IEnumerable<string[]> data) { }

类和接口需要稍作更改

public interface IHasHeader { string[] GetHeader(); }
public class DataList : List<Data>, IHasHeader { }
public class Data : IData { }

此时,实际上不再需要接口了。

该函数可以如下使用:

public DataList data = new DataList();
// data.Add(new Data(){ ... })
CreateDocument(data.GetHeader(), data.Select(x => x.GetData()));

我没有添加解决方案所需的声誉。如果有人将其转换为解决方案,我将愿意接受。

1 个答案:

答案 0 :(得分:0)

您可以编写一个方法来接受任何列表,方法是告诉它得到一个IEnumerable,基本类型List<T>IEnumerable<T>。这是一个非泛型类型。如果您在这里输入IList<SomeType>,则需要明确指定类型。

请参见下面的示例,如何在方法中使用IEnumerable并进行检查:

private class MyClass { }
private class MyClassWithInterface : IMyClass { }
private interface IMyClass { }

static void Main(string[] args)
{
    ITakeLists(new List<MyClass>()); // it is
    ITakeLists(new List<MyClassWithInterface>()); // isInstanceOf
    ITakeLists(new List<int>()); // it is not
    //ITakeLists(new MyClass()); // Error, is not derived from IEnumerable
}

private static void ITakeLists(IEnumerable myList)
{
    if (myList is List<MyClass>)
        Console.WriteLine("it is");
    else if(typeof(IMyClass).IsAssignableFrom(myList.GetType().GetGenericArguments()[0]))
        Console.WriteLine("isInstanceOf");
    else
        Console.WriteLine("it is not :(");
}