获取运行时间的最佳方式T的类型? [英] Best way to get runtime Type of T?

查看:65
本文介绍了获取运行时间的最佳方式T的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出下面的示例代码,我想要在一个泛型方法中获取运行时类型的T(在本例中为retrieveData)。当我创建一个XMLFilePersisting时,我使用的是接口,即ITransferable,而不是实现类型,因为在我的客户端中,我希望将它们全部列在一起:

 列表与LT; XMLFilePersisting< ITransferable>>所有; 

所以如果在retrieveData中我做typeof(T)应该返回ITransferable, info从文件加载项目。我可以想出如何做到这一点的唯一方法是通过在构造函数中传递ITransferable的实现者实例,但是这种感觉应该有更好的方式。建议?

 公共界面IPersisting< T> {
列表< T> retrieveData();
bool persistData(List< T> lst);
}

public interface ITransferable {
类型getRuntimeType();
}

公共类XMLFilePersisting< T> :IPersisting< T> T:ITransferable {
private只读T defaultT;
// ...
public XMLFilePersisting(string thefile,string thepath,T def){
// ...
defaultT = def;
}
...

public List< T> retrieveData(){
List< T> retVal =新列表< T>();
类型runType = defaultT.getRuntimeType();
字符串elemName = runType.Name;
using(FileStream fs = new FileStream(FQ_FILE_PATH,FileMode.Open,FileAccess.Read)){
using(XmlReader reader = XmlReader.Create(fs)){
// below line won不工作,typeof在compileTime
解析// XmlSerializer xmlSer = new XmlSerializer(typeof(T));
XmlSerializer xmlSer = new XmlSerializer(runType);
if(reader.ReadToFollowing(elemName)){//跳转到第一个测试,跳过ListofT
do {
T testVal =(T)xmlSer.Deserialize(reader);
retVal.Add(testVal);
}
while(reader.ReadToNextSibling(elemName));
}
} // end using xmlreader
} //使用FileStream结束
return retVal;
} // end retrieveData
} //结束类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

解决方案 div>

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

  //名称更改为更常规
var class1Loader = new XmlFilePersister< MyClass1>(MC1 .xml,myTempDirectory);
var class2Loader = new XmlFilePersister< MyClass2>(MC2.xml,myTempDirectory);

//可以在一个语句中完成所有操作......注意,这使用IEnumerable< T>的
//协方差。
IEnumerable< ITransferable> class1Results = class1Loader.RetrieveData();
IEnumerable< ITransferable> class2Results = class2Loader.RetrieveData();
var allResults = class1Results.Concat(class2Results).ToList();

误解了这个问题,如果是 persisters ,您希望成为在列表中,您可以使 XMLFilePersisting< T> 实现 IPersisting< ITransferable> 当您尝试存储数据而不是读取数据时...因为您需要从 ITransferable 转换为



基本上,我不知道你是否应该有两个接口: IDeserializer< ; out T> ISerializer< in T> 。使用这些协变和反变化的接口,您可以轻松地在不丢失信息或不需要执行时间检查的情况下拥有 List< IDeserializer< ITransferable>> 。 b

Given the example code below, I'd like to get the runtime type of T inside a generic method (in this case retrieveData). When I create an XMLFilePersisting I use the interface, namely ITransferable rather than the implementing Types since in my client I want to have a list of all of them together:

List<XMLFilePersisting<ITransferable>> allThem;

So if in retrieveData I do typeof(T) that should return ITransferable which doesn't give me enough info to load the items from the file. The only way I could figure out how to do this was by passing an instance of the implementor of ITransferable in the constructor, but this kind of feels like there should be a better way. Suggestions?

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

Additional info:

Client code looks like below. As you can see I need all

IPersisting<ITransferable>

instances, but the problem is in retrieveData, that makes typeof(T) = ITransferable which doesn't give me enough info to do the deserialization. That is why I pass concrete implmentations of ITransferable to the constructor (MyClass1, MyClass2). This seems to work, but feels like a hack.

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

A

解决方案

I would suggest that you make each XMLFilePersisting use the specific concrete type, but then combine the results into a List<ITransferable>. For example:

// 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();

Having misunderstood the question slightly, if it's the persisters you want to be in a list, you could make XMLFilePersisting<T> implement IPersisting<ITransferable> - although then you'd have problems when you try to store the data instead of reading it... because you'd need to cast from ITransferable to T, which could obviously fail at execution time.

Fundamentally, I wonder whether you should have two interfaces: IDeserializer<out T> and ISerializer<in T>. With those covariant and contravariant interfaces, you could easily have a List<IDeserializer<ITransferable>> without losing information or needing execution-time checking.

这篇关于获取运行时间的最佳方式T的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆