获取运行时 T 类型的最佳方法?
Best way to get runtime Type of T?
鉴于下面的示例代码,我想在泛型方法(在本例中为 retrieveData)中获取 T 的运行时类型。当我创建一个 XMLFilePersisting 时,我使用接口,即 ITransferable 而不是实现类型,因为在我的客户端中,我想要一个包含所有这些类型的列表:
List<XMLFilePersisting<ITransferable>> allThem;
因此,如果在 retrieveData 中我执行 typeof(T) 应该 return 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());
一个
我建议您让每个 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>>
而不会丢失信息或需要执行时检查。
鉴于下面的示例代码,我想在泛型方法(在本例中为 retrieveData)中获取 T 的运行时类型。当我创建一个 XMLFilePersisting 时,我使用接口,即 ITransferable 而不是实现类型,因为在我的客户端中,我想要一个包含所有这些类型的列表:
List<XMLFilePersisting<ITransferable>> allThem;
因此,如果在 retrieveData 中我执行 typeof(T) 应该 return 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());
一个
我建议您让每个 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>>
而不会丢失信息或需要执行时检查。