【问题标题】:Generics when trying to implement interface尝试实现接口时的泛型
【发布时间】:2018-03-08 05:34:49
【问题描述】:

问题:我有许多要解析的文件类型。每个解析一个文件并返回一个对象的结果(List<>)。我只想拥有一个IFileParser 接口,并在调用Parse 时指定解析器类型和返回集

我有这样的界面

public interface IFileParser
{
    TResponse Parse<TFileParserType,TResponse>(string file);
}

被注入到这样的服务中

private readonly IFileParser _fileParser;
 public CarService(IFileParser fileParser)

        {
            _fileParser = fileParser;

        }

被使用

var cardatas = _fileParser.Parse<CarFileParser, List<CarData>>("car.txt");
  var bikedatas = _fileParser.Parse<BikeFileParser, List<BikeData>>("bike.txt");

实现 - 这部分不起作用...为什么? 返回的错误是

无法将类型“System.Collections.Generic.List”隐式转换为“System.Collections.Generic.List


 public class CarFileParser : IFileParser
    {
        public List<CarData> Parse(string filePath)
        {
            return new List<CarData>() //does not work...why??
        }


        public TResponse Parse<TType, TResponse>(string file)
        {
            throw new NotImplementedException(); 
            //this is what it should be 
            //but how do I return a List<CarData> 
        }
    }

【问题讨论】:

  • 问题是什么?代码中TType有什么用?
  • @ChetanRanpariya 是“文件解析器类型”
  • CarDataClearingHouseSuperannuationData 有什么关系?为什么你尝试返回return new List&lt;CarData&gt;()是返回类型被指定为List&lt;ClearingHouseSuperannuationData&gt;
  • 你能为 CarData 和 ClearingHouseSuperannuationData 添加代码吗...这些类型兼容吗?
  • 好像是数组逆变问题...

标签: c# .net generics


【解决方案1】:

不声称这是答案。这有帮助吗:

public interface IFileParser<TResponse>
    {
        TResponse Parse(string file);
    }

    public class CarFileParser : IFileParser<List<CarData>>
    {
        public List<CarData> Parse(string file)
        {
            throw new NotImplementedException();
        }
    }

【讨论】:

  • 如果您能分享这段代码背后的想法,那就太好了。为什么这应该有助于反对 OP 的代码版本?
【解决方案2】:

首先,返回类型要与返回值匹配:

    public List<CarData> Parse(string filePath)
    {
        return new List<CarData>() //Will work..
    }

在进行类型转换时,列表不能转换为类。如果需要,请在类中创建一个属性。

    var cardatas = _fileParser.Parse<CarFileParserList, List<CarData>>("car.txt");

    class CarFileParser
    {
     public List<CarFile> CarFileParserList{get;set;}
    }

    public class CarFile
    {
     //create property here
    }

那么你可以使用这个代码:

     var cardatas = _fileParser.Parse<List<CarFile>, List<CarData>>("car.txt");
     var carFileParser= new CarFileParser();
     carFileParser.CarFileParserList=cardatas;

【讨论】:

  • 我试图避免在代码中实例化一个新的解析器,这样代码就不是我想要做的。我不想在代码中创建新的 CarFile Parser。我正在使用 IOC 注入它
【解决方案3】:

如果它总是返回一个列表,不妨试试

 List<TResponse> Parse<TFileParserType, TResponse>(string file);

然后

 List<CarData> cardatas = _fileParser.Parse<CarFileParser, CarData>("car.txt");

(或者可能是ICollection / IEnumerable

【讨论】:

    【解决方案4】:

    一般来说,我更喜欢像这样实现类型/接口。不确定这是否适用于您的注射。

    // Put the type of data on the interface / type
    public interface IFileParser<TData>
    {
        IEnumerable<TData> Parse(string file);
    }
    
    // Implement the interface
    public class CarParser : IFileParser<CarData>
    {
        ...
    }
    
    // The method where to inject the implementation:
    public IEnumerable<TData> Parse<TData>(IFileParser<TData> parser, string file)
    {
        return parser.Parse(file);
    }
    
    // The implementations would have to be injected here:
    private readonly IFileParser<CarData> _carFileParser;
    private readonly IFileParser<BikeData> _bikeFileParser;
    
    var carData = Parse(_carFileParser, file);
    var bikeData = Parse(_bikeFileParser, file);
    

    【讨论】:

    • 感谢@marsze,我看到的唯一问题是新 CarfileParser 实例的实例化。我想将它作为接口注入到服务中。目前我已经使用了 fileParser 的 2 个独立接口(汽车和自行车)。不是一个很好的解决方案
    • 我改变了答案。如果您需要多个实现,则不能只有 一个 _fileParser 字段。
    • @kurasa 没有反馈!?
    • 对不起..一直很忙...我最终选择了 3 个不同的界面,因为我无法让它工作,我不得不交付它..你的答案正是我必须开始的有但无法使用带有泛型的单个接口来创建它...我怀疑这对我来说很简单我错过了..感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2021-09-28
    • 2023-02-09
    相关资源
    最近更新 更多