【问题标题】:Best way to get runtime Type of T?获得运行时 T 类型的最佳方法?
【发布时间】:2015-02-07 07:06:06
【问题描述】:

鉴于下面的示例代码,我想在泛型方法(在本例中为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)。这似乎行得通,但感觉就像一个 hack。

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

一个

【问题讨论】:

  • 首先要改变:开始遵循 .NET 命名约定。如果您满足他们的命名期望,它会让其他人更容易阅读您的代码。
  • 接下来,您将在哪里传递有关您想要的实际类型的信息完全不清楚。您的“当我创建 XMLFilePersisting 时,我使用接口,即 ITransferable 而不是实现类型,因为在我的客户端中,我希望将所有这些类型放在一起”并没有对我解释太多。您是否正在创建XMLFilePersisting 的多个实例?如果是这样,为什么不为每个具体类型创建一个实例,然后从结果中构建一个大的List&lt;ITransferable&gt;
  • 对不起。我编辑了我的问题,以更好地显示我的调用代码中的相关部分
  • 好吧,我们仍然不知道您为什么希望他们成为 IPersisting&lt;ITransferable&gt; 而不是 IPersisting&lt;MyClass1&gt;IPersisting&lt;MyClass2&gt;,这显然可以解决问题。
  • @JonSkeet 在一天结束时,我希望他们都进入一个强类型列表

标签: c# .net generics


【解决方案1】:

我建议您让每个XMLFilePersisting 使用特定的具体类型,然后将结果组合成List&lt;ITransferable&gt;。例如:

// 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&lt;T&gt; 实现 IPersisting&lt;ITransferable&gt; - 虽然当你尝试时你会遇到问题存储数据而不是读取它...因为您需要从ITransferable 转换为T,这显然会在执行时失败。

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

【讨论】:

  • 你有错字吗,当两次调用class1Loader.RetrieveData();class2Results 应该调用class2Loader.RetrieveData();
  • 不幸的是,我认为这对我不起作用,因为我需要 List&lt;IPersisting&lt;ITransferable&gt;&gt; 而不是 List&lt;ITransferable&gt;。由于 IPersisting 是不变的(对吗?)我不能从 XMLFilePersisting&lt;MyClass1&gt; 向上转换到 IPersisting&lt;ITransferable&gt; 其他线程已经指向反射,但我宁愿只保留存储任意 T 引用的“hack”。
  • @publicwireless:啊,我明白了。让XMLFilePersisting&lt;T&gt; 只实现IPersisting&lt;ITransferable&gt; 怎么样?或者你可以把它变成两种类型的通用......如果不了解更多上下文,这有点难以判断。
  • @publicwireless:我已经编辑了我的答案以提供更多细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2010-09-06
  • 2016-01-25
  • 2010-09-06
  • 2012-04-05
  • 2012-07-04
  • 1970-01-01
相关资源
最近更新 更多