2015-09-11 33 views
7

、私は以下のクラスを構築しようとしている:無効なキャスト

public class ConfigurationElementCollection<TElement, TParent> 
    where TElement : ParentedConfigElement<TParent>, new() 
    where TParent : class 
{ 
    public TParent ParentElement { get; set; } 

    protected ConfigurationElement CreateNewElement() 
    { 
     //************************************************** 
     //COMPILER GIVES TYPE CONVERSION ERROR ON THIS LINE! 
     //************************************************** 
     return new TElement { ParentCollection = this }; 
    } 
} 

public class ParentedConfigElement<TParent> : ConfigurationElement where TParent : class 
{ 
    internal ConfigurationElementCollection<ParentedConfigElement<TParent>, TParent> 
     ParentCollection { get; set; } 

    protected TParent Parent 
    { 
     get 
     { 
      return ParentCollection != null ? ParentCollection.ParentElement : null; 
     } 
    } 
} 

上記のコードのコメントが示すように、コンパイラはエラーを与える:

Cannot implicitly convert type 'Shared.Configuration.ConfigurationElementCollection<TElement, TParent>' to 'Shared.Configuration.ConfigurationElementCollection<Shared.Configuration.ParentedConfigElement<TParent>,TParent>

私が指定したジェネリック型の制約のため、TElementShared.Configuration.ParentedConfigElement<TParent>であることもコンパイラーが知っているため、このエラーは予想されません。

はそれでも、私は明示この問題を乗り越えるためにタイプをキャストします図:

(ConfigurationElementCollection<ParentedConfigElement<TParent>,TParent>) this; 

は残念ながら、私は同じコンパイラエラーを取得します。なぜこうなった?私は何を間違えたのですか? dynamicタイプに頼らなくても、これを修正するにはどうすればよいですか?

答えて

2

あなたの問題はあなたがタイプCEC<A, B>を持っていることであり、あなたがList<string>を割り当てることができないとほとんど同じように、あなたが行うことができないタイプCEC<C<A>,B>のプロパティに割り当てしようとしているこの答えを見てみましょうList<object>のストレージは、objectに由来していますが、stringです。 ParentedConfigElementでプロパティが内蔵されているので、あなたはまた、すべての消費者に、この実装の詳細の公開を回避するために内部インターフェースを作ることができます

public interface IConfigurationElementCollection<TParentedConfig, TParent> 
    where TParentedConfig : ParentedConfigElement<TParent> 
    where TParent : class 
{ 
    TParent ParentElement { get; } 
} 

public class ConfigurationElementCollection<TElement, TParent> : IConfigurationElementCollection<ParentedConfigElement<TParent>, TParent> 
    where TElement : ParentedConfigElement<TParent>, new() 
    where TParent : class 
{ 
    public TParent ParentElement { get; set; } 

    protected ConfigurationElement CreateNewElement() 
    { 
     //************************************************** 
     //COMPILER NO LONGER GIVES TYPE CONVERSION ERROR 
     //BECAUSE this IMPLEMENTS THE EXPECTED INTERFACE! 
     //************************************************** 
     return new TElement { ParentCollection = this }; 
    } 
} 

public class ParentedConfigElement<TParent> : ConfigurationElement where TParent : class 
{ 
    internal IConfigurationElementCollection<ParentedConfigElement<TParent>, TParent> 
     ParentCollection { get; set; } 

    protected TParent Parent 
    { 
     get 
     { 
      return ParentCollection != null ? ParentCollection.ParentElement : null; 
     } 
    } 
} 

暗黙の演算子やダイナミックを使用しないクリーンなソリューションは、インターフェイスを使用することですそのようなことがあなたにとって懸念事項であるかどうか。

+0

CEC のジェネリック制約は、提供したインターフェイスとまったく同じことを暗黙に指摘していますが、一般的な制約は無視されているように感じられます。それでも、「ダイナミック」タイプを使用せずにこの作業を行う方法を見つけて本当に嬉しく思っています。 –

+0

これを行うには、組成を使用する方がはるかに優れています。私の答えを取り除く。 –

+0

しかし、ジェネリック制約はインターフェイスとまったく同じことを言っていませんが、最初の型引数は 'ParentedConfigElement 'から継承しているだけです。つまり、 'TElement'は' ParentedConfigElement 'に代入可能ですが、その継承はジェネリック型の型パラメータに拡張されません。 – Erik

4

https://stackoverflow.com/a/6529618/5071902

protected ConfigurationElement CreateNewElement() 
{ 
    return (TElement)Activator.CreateInstance(typeof(TElement), this); 
} 

You will need a constructor with this signature, setting the ParentCollection property.

に基づいて、あなたもリフレクションを使用して試すことができます。 https://stackoverflow.com/a/6529622/5071902

+0

Activator.CreateInstanceは、ターゲットオブジェクトにデフォルトのコンストラクタがない場合にのみ必要です。私の例では、実際にはデフォルトのコンストラクタを持っています。それは私が初期化しているプロパティです...コンストラクタパラメータではありません。 –

関連する問題