J'essaie de convertir un objet d'un certain type en une interface qu'il implémente à l'aide de Convert.ChangeType()
, mais une variable InvalidCastException
est émise car l'objet doit implémenter IConvertible .
Les types:
public IDocumentSet : IQueryable {}
public IDocumentSet<TDocument> : IDocumentSet, IQueryable<TDocument> {}
public XmlDocumentSet<TDocument> : IDocumentSet<TDocument> {}
Extrait du code où l'erreur se produit:
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});
}
}
}
Maintenant, je ne comprends pas pourquoi cela se produit exactement (car XmlDocumentSet
n'est pas un type de valeur) et XmlDocumentSet<'1>
implémente IDocumentSet<'1>
. Est-ce que je manque quelque chose? Ou y a-t-il un moyen plus facile de réaliser ce que je fais?
L'interface IConvertible est conçue pour permettre à une classe de se convertir en toute sécurité à un autre type. L'appel Convert.ChangeType utilise cette interface pour convertir en toute sécurité un type à un autre.
Si vous ne connaissez pas les types au moment de la compilation, vous serez forcé d'essayer un transtypage à l'exécution. Ceci est discuté dans une question très similaire ici Convertir une variable en dactylographie uniquement connue au moment de l'exécution? .
Implémenter IConvertible est très pénible pour de tels scénarios légitimes et, à mon avis, une perte de temps de développement. Le mieux est d'implémenter une méthode abstraite dans la classe de base, que votre classe dérivée implémentera pour se retourner elle-même. ci-dessous est l'exemple.
//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;
}
Ce travail parfaitement et sans besoin de IConvertible douloureux. Dans l'exemple ci-dessus, la classe de base implémente une interface avec <ID, T>
et la classe dérivée comporte une référence à la classe DocumentTypeMap. La classe DocumentTypeMap implémente l'interface avec <ID>
.