如何正确处理由泛型类组成的列表,其方法也具有泛型返回值

本文关键字:方法 返回值 泛型 列表 理由 处理 何正确 泛型类 | 更新日期: 2023-09-27 17:51:12

我相信这个问题的答案很简单,但由于我一直在思考这个问题,我可能很难看到整体情况。

我想加载多个文件(在本例中是JSON),所以我创建了一个DataLoader类来处理这个问题。在这个类中,我正在创建一个ILoaders列表,该类将迭代和加载,以便在将来如果我使用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类并使其实现ILoader接口时,我注意到我必须将ILoader转换为通用接口:我将始终需要提供JSONLoader将放入数据的根类T,并且还需要它灵活并返回包含加载数据的List<T>

所以现在我的JSONLoader类读为:

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

和illoader:

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

现在当我回到DataLoader类时,正如您所看到的,我失去了调用ILoader的灵活性,因为我需要告诉正在使用的泛型类是什么。

我试图将其封装在另一个接口中,但随后DataLoader中的loader.Load()调用被打破,因为它返回List<T>

现在我的感觉是,要修好一边,就得弄坏另一边。我一直在努力思考抽象类和接口的良好组合,以相应地隔离所有内容,但我在可视化中遇到了一个大麻烦(我对c#相当陌生,还没有头脑敏捷地看到我应该做什么和封装)。

我将此作为学习c#的练习,并希望尽可能使用最佳编程实践。我想有一个健壮的代码,没有重复和类之间的依赖最小的数量。我也希望得到一个解释,而不仅仅是一个工作代码。谢谢你!

如何正确处理由泛型类组成的列表,其方法也具有泛型返回值

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

这是因为List<T>不是协变的。如果你想让它工作,而不是暴露List<T>,你可以暴露IEnumerable<T>,它是T的协变,也使你的Loader<T>Loader<out T>协变:

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