获取运行时类型的T的最佳方法是什么?

时间:2015-02-07 07:06:07

标签: c# .net generics

鉴于下面的示例代码,我想在泛型方法(在本例中为retrieveData)中获取T的运行时类型。当我创建XMLFilePersisting时,我使用接口,即ITransferable而不是实现类型,因为在我的客户端中我想要一起列出所有这些:

List<XMLFilePersisting<ITransferable>> allThem;

因此,如果在retrieveData中我执行typeof(T)应该返回ITransferable,它不会给我足够的信息来加载文件中的项目。我可以弄清楚如何做到这一点的唯一方法是在构造函数中传递ITransferable的实现者的实例,但这种感觉应该有更好的方法。建议?

public interface IPersisting<T> {
        List<T> retrieveData();
        bool persistData(List<T> lst);
    }

public interface ITransferable {
    Type getRuntimeType();
}

public class XMLFilePersisting<T> : IPersisting<T> where T : ITransferable {
    private readonly T defaultT;
    //...
    public XMLFilePersisting(string thefile, string thepath, T def) {
        //...
        defaultT = def;
    }
    ...

    public List<T> retrieveData() {
      List<T> retVal = new List<T>();
      Type runType = defaultT.getRuntimeType();
      string elemName = runType.Name;
      using (FileStream fs = new FileStream(FQ_FILE_PATH, FileMode.Open, FileAccess.Read)) {
        using (XmlReader reader = XmlReader.Create(fs)) {
           //below line won't work, typeof resolves at compileTime      
           //XmlSerializer xmlSer = new XmlSerializer(typeof(T));
           XmlSerializer xmlSer = new XmlSerializer(runType);
           if (reader.ReadToFollowing(elemName)) { //go to the first test, skipping over ListofT
              do {
                 T testVal = (T)xmlSer.Deserialize(reader);
                 retVal.Add(testVal);
                }
              while (reader.ReadToNextSibling(elemName));
           }
         } //end using xmlreader
      } //end using FileStream
    return retVal;
  } //end retrieveData
} //end class XMLFilePersisting

其他信息:

客户端代码如下所示。如你所见,我需要所有

IPersisting<ITransferable>

实例,但问题在于retrieveData,这使得typeof(T)= ITransferable,它没有给我足够的信息来进行反序列化。这就是为什么我将ITransferable的具体实现传递给构造函数(MyClass1,MyClass2)。这似乎有效,但感觉就像一个黑客。

IPersisting<ITransferable> xfpMC1 = new XMLFilePersisting<ITransferable>("persistedMC1.xml", myTempDirectory, new MyClass1());
IPersisting<ITransferable> xfpMC2 = new XMLFilePersisting<ITransferable>("persistedMC2.xml", myTempDirectory, new MyClass2());

A

1 个答案:

答案 0 :(得分:3)

我建议你让每个XMLFilePersisting使用特定的具体类型,然后将结果合并到List<ITransferable>。例如:

// Names changed to be more conventional
var class1Loader = new XmlFilePersister<MyClass1>("MC1.xml", myTempDirectory");
var class2Loader = new XmlFilePersister<MyClass2>("MC2.xml", myTempDirectory");

// Could do all of this in one statement... note that this uses the
// covariance of IEnumerable<T>
IEnumerable<ITransferable> class1Results = class1Loader.RetrieveData();
IEnumerable<ITransferable> class2Results = class2Loader.RetrieveData();
var allResults = class1Results.Concat(class2Results).ToList();

稍微误解了这个问题,如果 persisters 你想要在列表中,你可以XMLFilePersisting<T>实现IPersisting<ITransferable> - 尽管如此你当您尝试存储数据而不是阅读数据时,会遇到问题...因为您需要从ITransferable投射到T,很可能在执行时失败了。

从根本上说,我想知道你是否应该有两个接口:IDeserializer<out T>ISerializer<in T>。使用这些协变和逆变接口,您可以轻松获得List<IDeserializer<ITransferable>>而不会丢失信息或需要执行时间检查。