如何使用也具有通用 returns 的方法正确处理由通用 类 组成的列表

How to correctly handle a list made of generic classes with methods that also have generic returns

我认为这个问题的答案很简单,但是由于我一直在这个问题上苦思冥想,所以我可能无法看清全局。

我想加载多个文件(在本例中,JSON),所以我创建了一个 DataLoader class 来处理这个问题。在这个 class 中,我正在创建一个 ILoaders 的列表,class 将迭代和加载它,以便将来如果我使用 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);
        }
    }
}

当我创建 JSONLoader class 并使其实现 ILoader 接口时,我注意到我必须将 ILoader 转换为通用接口:我将总是需要提供根 class TJSONLoader 将把数据放入其中,还需要它是灵活的,return List<T> 包含数据已加载。

所以现在我的 JSONLoader class 读作:

public class JSONLoader<T> : ILoader<T> where T : IDataLoaded, new(){

    private string fileContents;
    private T output = new T();
    private List<T> outputlist;

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

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

和 ILoader:

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

现在,当我回到 DataLoader class 时,如您所见,我失去了调用 ILoader 的灵​​活性,因为我需要告诉正在使用通用 class。

我试图将它封装在另一个接口中,但是 DataLoader 中的 loader.Load() 调用被破坏了,因为它 return 是一个 List<T>.

现在我觉得要修复一侧,我会破坏另一侧。我一直在尝试思考抽象 classes 和接口的良好组合以相应地隔离所有内容,但我在想象它如何适合时遇到了很大的麻烦(我对 C# 很陌生并且不我还没有头脑灵活地看到我应该做什么和封装)。

我将其用作学习 C# 的练习,并希望尽可能使用最佳编程实践。我想要一个健壮的代码,没有重复并且 classes 之间的依赖性最少。我也希望得到一个解释,而不仅仅是一个工作代码。谢谢!

I have some issues with the interfaces (it complains that it cannot convert JSONLoader expression to type ILoader)

那是因为 List<T> 不是协变的。如果你想让它工作,而不是公开 List<T>,你可以公开一个 IEnumerable<T>,它在 T 中是协变的,并且还使你的 Loader<T> 与 [=16] 是协变的=]:

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;
    }
}