【发布时间】:2014-03-04 09:11:27
【问题描述】:
我正在尝试实现一个允许从文件中读取和解释行的系统。
我需要管理不同的文件格式。为此,我有一个抽象的 Importer 类,它被继承并以不同的方式实现(基于文件格式)。
文件的行可以产生不同的对象,所以我创建了一个通用接口,知道如何解析行,验证它等:public interface ILineImporter<ObjType> where ObjType : IImportableObject
具体的Importer 类通过重写的抽象方法public abstract ILineImporter<IImportableObject> GetLineImporter(string line); 知道将哪个LineImporter 用于给定的行。
问题是在这个方法的实现中,返回的类型取决于具体的Importer和line:
public override ILineImporter<IImportableObject> GetLineImporter(string line)
{
// TODO: Return the appropriate LineImporter for the given line
// For the example, I always return a MyObjectALineImporter, but it can potentially be any ILineImporter<IImportableObject>
return new MyObjectALineImporter();
}
这不会编译,因为编译器无法将MyObjectALineImporter 隐式转换为ILineImporter<IImportableObject>。
如果我添加 in 或 out 关键字来使用协变/逆变,编译器会指出我的泛型接口不是协变/逆变有效的。
下面是简化的源代码,您可以将其放入标准控制台应用程序中以重现该问题:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ConsoleApplication2
{
public interface IImportableObject { }
public class MyObjectA : IImportableObject { }
public interface ILineImporter<ObjType> where ObjType : IImportableObject
{
ObjType GetObject();
bool IsObjectValid(ObjType o);
}
/// <summary>
/// Concrete class that knows how to get the appropriate MyObjectA instance, validate it, etc.
/// </summary>
public class MyObjectALineImporter : ILineImporter<MyObjectA>
{
public MyObjectA GetObject()
{
Console.WriteLine("GetObject");
return new MyObjectA(); // For the example, I create a new instance but this method can potentially return an existing object from DB.
}
public bool IsObjectValid(MyObjectA o)
{
Console.WriteLine("IsValid");
// TODO : Test if the object is valid
return true;
}
}
public abstract class Importer
{
public abstract ILineImporter<IImportableObject> GetLineImporter(string line);
public void Importe(string text)
{
using (StringReader reader = new StringReader(text))
{
string line;
while ((line = reader.ReadLine()) != null)
{
var lineImporter = this.GetLineImporter(line);
var obj = lineImporter.GetObject();
bool isValid = lineImporter.IsObjectValid(obj);
}
}
}
}
public class ConcreteImporter1 : Importer
{
public override ILineImporter<IImportableObject> GetLineImporter(string line)
{
// TODO: Return the appropriate LineImporter for the given line
// For the example, I always return a MyObjectALineImporter, but it can potentially be another ILineImporter
return new MyObjectALineImporter();
}
}
class Program
{
static void Main(string[] args)
{
Importer importer = new ConcreteImporter1(); // TODO : Retrieve the appropriate Importer with a Factory.
importer.Importe(string.Empty);
Console.ReadKey();
}
}
}
处理这个问题的正确方法是什么?
【问题讨论】:
标签: c# generics covariance contravariance