C# 如何正确处理由泛型类和具有泛型返回的方法组成的列表

C# 如何正确处理由泛型类和具有泛型返回的方法组成的列表,c#,json,generics,interface,abstract-class,C#,Json,Generics,Interface,Abstract Class,我相信这个问题的答案很简单,但由于我已经在这个问题上绞尽脑汁了一段时间,我可能很难看清全局 我想加载多个文件(在本例中为JSON),因此我创建了一个DataLoader类来处理这个问题。在这个类中,我创建了一个类将迭代和加载的iloader列表,这样将来如果我使用JSON以外的东西,抽象就已经实现了 public class DataLoader{ private List<IDataLoaded> allDataLoaded = new List<IDataLoad

我相信这个问题的答案很简单,但由于我已经在这个问题上绞尽脑汁了一段时间,我可能很难看清全局

我想加载多个文件(在本例中为JSON),因此我创建了一个
DataLoader
类来处理这个问题。在这个类中,我创建了一个类将迭代和加载的
iloader
列表,这样将来如果我使用JSON以外的东西,抽象就已经实现了

public class DataLoader{

    private List<IDataLoaded> allDataLoaded = new List<IDataLoaded>();

    private List<ILoader> loaderLists = new List<ILoader> (){
        new JSONLoader<RootSpacecrafts>(),
        new JSONLoader<RootWeapons>()
    };

    public void LoadData(){
        foreach(ILoader loader in loaderLists){
            loader.Read ();
            IDataLoaded dataLoaded = loader.Load ();
            allDataLoaded.Add(dataLoaded);
        }
    }
}
以及ILoader:

public interface ILoader<T>{
    void Read();
    List<T> Load();
}
公共接口ILoader{
无效读取();
列表加载();
}
现在,当我回到
DataLoader
类时,正如您所看到的,我失去了调用
ILoader
的灵活性,因为我需要告诉您使用的泛型类是什么

我试图将其封装在另一个接口中,但是
DataLoader
中的
loader.Load()
调用被中断,因为它返回一个
列表

现在我觉得,如果要在一边修好,我会打破另一边。我一直在尝试将抽象类和接口很好地结合起来,以相应地隔离所有内容,但我在可视化所有内容时遇到了很大的困难(我对C#还相当陌生,还没有足够的思维敏捷性来了解我应该做什么和封装)

我将此作为学习C#的练习,并希望尽可能使用最佳编程实践。我希望有一个健壮的代码,没有重复,并且类之间的依赖关系最少。我还希望得到一个解释,而不仅仅是一个工作代码。谢谢大家!

我对接口有一些问题(它抱怨它不能 将JSONLoader表达式转换为类型 ILoader)

这是因为
List
不是协变的。如果您希望这样做,而不是公开
列表
,您可以公开在
T
中协变的
IEnumerable
,还可以使您的
加载器
加载器
协变:

公共类数据加载器
{
private IEnumerable allDataLoaded=新列表();
私有IEnumerable LoaderList=新建
列表
{
新的JsonLoader(),
新的JsonLoader()
};
公共void LoadData()
{
foreach(装载机列表中的ILoader装载机)
{
loader.Read();
allDataLoaded=loader.Load();
}
}
}
公共接口ILoader
{
无效读取();
IEnumerable Load();
}
公共类JsonLoader:ILoader,其中T:IDataLoaded,new()
{
私有字符串文件内容;
私有T输出=新T();
私有IEnumerable输出列表;
公共无效读取()
{
fileContents=File.ReadAllText(“”);
outputlist=JsonConvert.DeserializeObject(fileContents);
}
公共IEnumerable负载()
{
返回输出列表;
}
}

您在
ILoader
中有
T
的哪些用法?仅用于加载值?另外,我假设
RootSpacecrafts
rootwearms
实现
IDataLoaded
T
用于将json反序列化为正确的根类,并返回反序列化数据的相应
列表。是的,它们实现了
IDataLoaded
。目前,这只是为了获取JSON文件的路径,它是根类的一个属性。迭代
foreach(LoaderList中的ILoader loader)
应该会给您带来您想要的灵活性,不是吗?非常感谢您的帮助和时间,Yuval:)
根据我的理解,协变类型参数“t”必须在“ILoader.Load()”上始终有效,在界面中同时使用协方差和逆变方差时会发生这种情况。但ILoader似乎是协变的,而不是反变的。你知道这里的冲突是什么吗?如果
T
是协变的,它不能作为输入参数传递给
ILoader
中的方法。我需要实例化它以获得具有文件路径的属性。它看起来很难看,但我希望一旦我开始工作,它会组织得更好。再次感谢你的帮助!只是一个更新:因为我当前使用的是Unity,所以IEnumerable似乎不是协变的:
公共接口IEnumerable:IEnumerable
,因此出现了错误。尽管如此,这是了解协方差有用性的一个很好的练习!
public interface ILoader<T>{
    void Read();
    List<T> Load();
}
public class DataLoader
{
    private IEnumerable<IDataLoaded> allDataLoaded = new List<IDataLoaded>();
    private IEnumerable<ILoader<IDataLoaded>> loaderLists = new
                                                            List<ILoader<IDataLoaded>>
    {
        new JsonLoader<RootSpacecrafts>(),
        new JsonLoader<RootWeapons>()
    };

    public void LoadData()
    {
        foreach (ILoader<IDataLoaded> loader in loaderLists)
        {
            loader.Read();
            allDataLoaded = loader.Load();
        }
    }
}

public interface ILoader<out T>
{
    void Read();
    IEnumerable<T> Load();
}

public class JsonLoader<T> : ILoader<T> where T : IDataLoaded, new()
{
    private string fileContents;
    private T output = new T();
    private IEnumerable<T> outputlist;

    public void Read()
    {
        fileContents = File.ReadAllText("");
        outputlist = JsonConvert.DeserializeObject<List<T>>(fileContents);
    }

    public IEnumerable<T> Load()
    {
        return outputlist;
    }
}