我正在尝试将某个类型的对象转换为它使用Convert.ChangeType()
实现的接口,但是InvalidCastException
会被抛出,因为该对象必须实现IConvertible。
类型:
public IDocumentSet : IQueryable {}
public IDocumentSet<TDocument> : IDocumentSet, IQueryable<TDocument> {}
public XmlDocumentSet<TDocument> : IDocumentSet<TDocument> {}
从发生错误的代码中摘录:
private readonly ConcurrentDictionary<Type, IDocumentSet> _openDocumentSets = new ConcurrentDictionary<Type, IDocumentSet>();
public void Commit()
{
if (_isDisposed)
throw new ObjectDisposedException(nameof(IDocumentStore));
if (!_openDocumentSets.Any())
return;
foreach (var openDocumentSet in _openDocumentSets)
{
var documentType = openDocumentSet.Key;
var documentSet = openDocumentSet.Value;
var fileName = GetDocumentSetFileName(documentType);
var documentSetPath = Path.Combine(FolderPath, fileName);
using (var stream = new FileStream(documentSetPath, FileMode.Create, FileAccess.Write))
using (var writer = new StreamWriter(stream))
{
var documentSetType = typeof (IDocumentSet<>).MakeGenericType(documentType);
var writeMethod = typeof (FileSystemDocumentStoreBase)
.GetMethod(nameof(WriteDocumentSet), BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(documentSetType);
var genericDocumentSet = Convert.ChangeType(documentSet, documentSetType); <-------
writeMethod.Invoke(this, new[] {writer, genericDocumentSet});
}
}
}
现在,我无法理解为什么会发生这种情况(因为XmlDocumentSet
不是值类型)而且XmlDocumentSet<'1>
实现了IDocumentSet<'1>
。我错过了什么吗?或者有更简单的方法来实现我正在做的事情?
IConvertible接口旨在允许类安全地将自身转换为另一个类型。 Convert.ChangeType调用使用该接口将一种类型安全地转换为另一种类型。
如果您在编译时不知道类型,那么您将被迫尝试运行时强制转换。这是在一个非常类似的问题讨论Convert variable to type only known at run-time?。
对于这种合法的场景,实现IConvertible是一件很痛苦的事情,在我看来浪费了宝贵的开发时间。最好是在基类中实现一个抽象方法,派生类将实现该方法以返回自身。下面是一个例子。
//implement this in base class
protected abstract BaseDocumentTypeMap<ID> ConvertDocType(T doc);
//usage of the abstract code
BaseDocumentTypeMap<ID> beDocType;
//loop through all the document types and check if they are enabled
foreach(T doc in result)
{
beDocType = ConvertDocType(doc);
//some action
}
//implement this in the derived class
protected override BaseDocumentTypeMap<int> ConvertDocType(DocumentTypeMap doc)
{
return doc;
}
这项工作完美无需痛苦的IConvertible。在上面的例子中,基类是用<ID, T>
实现的接口,派生类有一个对DocumentTypeMap类的引用,而DocumentTypeMap类正在用<ID>
实现接口