Object must implement IConvertible (InvalidCastException) while casting to interface
Solution 1
The IConvertible interface is designed to allow a class to safely convert itself to another Type. The Convert.ChangeType call uses that interface to safely convert one type to another.
If you do not know the Types at compile time then you will be forced to attempt a runtime cast. This is discussed in a very similar question here Convert variable to type only known at run-time?.
Solution 2
Implementing IConvertible is a lot of pain for such legitimate scenarios, and in my opinion waste of precious development time. Best is to implement an abstract method in the base class, which your derived class will implement to return itself. below is the example.
//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;
}
This work perfectly and without a need of painful IConvertible. in the above example the base class is implementing an interface with <ID, T>
and derived class has a reference to the DocumentTypeMap class, and DocumentTypeMap class is implementing the interface with <ID>
artganify
Updated on July 17, 2022Comments
-
artganify almost 2 years
I'm trying to cast an object of a certain type to an interface it implements using
Convert.ChangeType()
, however anInvalidCastException
gets thrown because the object must implement IConvertible.The types:
public IDocumentSet : IQueryable {} public IDocumentSet<TDocument> : IDocumentSet, IQueryable<TDocument> {} public XmlDocumentSet<TDocument> : IDocumentSet<TDocument> {}
Excerpt from code where the error happens:
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}); } } }
Now, I'm failing to understand why exactly this happens (as
XmlDocumentSet
is not a value type) andXmlDocumentSet<'1>
implementsIDocumentSet<'1>
. Am I missing something? Or is there an easier way to achieve what I'm doing? -
Philip about 4 yearsAlthough I didn't try your method, but thank you for warning me about how painful this is