web-dev-qa-db-ja.com

オブジェクトは、インターフェイスへのキャスト中にIConvertible(InvalidCastException)を実装する必要があります

特定のタイプのオブジェクトを、Convert.ChangeType()を使用して実装するインターフェイスにキャストしようとしていますが、オブジェクトはIConvertibleを実装する必要があるであるため、InvalidCastExceptionがスローされます。

タイプ:

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>。何か不足していますか?または、私がやっていることを達成する簡単な方法はありますか?

11
artganify

IConvertibleインターフェイスは、クラスが別のTypeに安全に変換できるように設計されています。 Convert.ChangeType呼び出しは、そのインターフェイスを使用して、あるタイプを別のタイプに安全に変換します。

コンパイル時にタイプがわからない場合は、ランタイムキャストを試みる必要があります。これは、ここで非常によく似た質問で説明されています 実行時にのみ既知の型に変数を変換しますか?

2
PhillipH

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>とのインターフェースを実装しています

1
Kalpesh Popat