wake-up-neo.com

Das Objekt muss IConvertible (InvalidCastException) während der Umwandlung in die Schnittstelle implementieren

Ich versuche, ein Objekt eines bestimmten Typs in eine Schnittstelle umzuwandeln, die es mit Convert.ChangeType() implementiert. Eine InvalidCastException wird jedoch geworfen, weil das Objekt IConvertible implementieren muss.

Die Typen:

public IDocumentSet : IQueryable {}

public IDocumentSet<TDocument> : IDocumentSet, IQueryable<TDocument> {}

public XmlDocumentSet<TDocument> : IDocumentSet<TDocument> {}

Auszug aus dem Code, wo der Fehler auftritt:

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});
        }
    }
}

Nun verstehe ich nicht, warum genau dies passiert (da XmlDocumentSet kein Werttyp ist) und XmlDocumentSet<'1>IDocumentSet<'1> implementiert. Fehlt mir etwas? Oder gibt es einen einfacheren Weg, um das zu erreichen, was ich tue?

11
artganify

Die IConvertible-Schnittstelle ermöglicht es einer Klasse, sich sicher in einen anderen Typ umzuwandeln. Der Aufruf Convert.ChangeType verwendet diese Schnittstelle, um einen Typ sicher in einen anderen zu konvertieren.

Wenn Sie die Typen zum Zeitpunkt der Kompilierung nicht kennen, müssen Sie eine Laufzeitumwandlung versuchen. Dies wird in einer sehr ähnlichen Frage hier diskutiert. Konvertiere Variable nur zur Laufzeit zur Laufzeit? .

2
PhillipH

Die Implementierung von IConvertible ist für solche legitimen Szenarien sehr schmerzhaft und meiner Meinung nach eine Verschwendung wertvoller Entwicklungszeit. Am besten implementieren Sie eine abstrakte Methode in der Basisklasse, die Ihre abgeleitete Klasse implementiert, um sich selbst zurückzugeben. Unten ist das Beispiel.

//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;
        }

Dies funktioniert perfekt und ohne schmerzhafte IConvertible. Im obigen Beispiel implementiert die Basisklasse eine Schnittstelle mit <ID, T>, und die abgeleitete Klasse enthält eine Referenz auf die DocumentTypeMap-Klasse. Die DocumentTypeMap-Klasse implementiert die Schnittstelle mit <ID>.

0
Kalpesh Popat