0

次の宣言を持つ2つのクラスがあります。

  • abstract class ClassBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject
  • abstract class ServiceBase<T> where T : myType

他に2つのクラスがあり、それぞれから1つずつ継承します。これで、 ClassAliExpressServiceAliExpressを呼び出すことができます。2つのサービスクラスは他の2つと同じプロジェクトにないことに注意してください。

アイデアは、ServiceBaseクラスで次のようなプロパティを宣言protected ClassBase<T,System.Data.Objects.DataClasses.EntityObject> Class { get; set; }し、継承されたサービスのコンストラクタで次のようなプロパティを宣言できるということです。this.Class = ClassInheritedInstance

私はすでにアイデアを実装しましたが、Service合計クラスコンストラクターでClassプロパティを割り当てると、次のエラーが発生します。

タイプ「ClassAliExpress」を「ClassBase<T、S>」に暗黙的に変換することはできません

ClassAliExpressは確かにClass<T,S>...の仕様であることに注意してください。コンパイラが型を正しく認識できないように見えるだけです。また、クラスプロパティの宣言をprotected ClassBase<T, EntityObjectInherited>機能するように変更すると、EntityObjectAliExpressSystem.Data.Objects.DataClasses.EntityObject...の実装になります。なぜ問題があるのか​​わかりません。

アップデート1

コンパイル時にのタイプClassInheritedは既知であることに注意してください。その宣言は次のとおりです。public class ClassInherited : ClassBase<myTypeInherited, EntityObjectInherited>

4

3 に答える 3

1

最初の答え

ServiceAliExpress-classで使用できない理由protected ClassBase<T,S> Class { get; set; }は、プロパティClassの型を宣言するために必要なS型がわからないためです。

オプションが必要です:

  • サービスタイプの仕様にSタイプを含めます。abstract class ServiceBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject

  • Sタイプを使用せずにクラス継承オブジェクトを参照できるように、Tタイプのみを使用してClassBaseのインターフェースを実装します。次に、Sタイプを指定する必要がないため、(インターフェイスタイプの)サービスクラスにプロパティを含めることができます。

generic-type-checkingは実行時ではなく、コンパイル時にチェックされることに注意してください。そうでなければ、強い型付けではないでしょう。

アップデート

キャストが機能しない理由は、タイプClassBase<T, EntityObjectInherited>がと等しくないか、キャストできないためClassBase<T, System.Data.Objects.DataClasses.EntityObject>です。共分散はクラスタイプでは機能せず、インターフェイスタイプでのみ機能します。

ここでの解決策は、インターフェースを操作することだと思います。クラスベースのインターフェースを使用しますIClassBase<T>。そうすれば、クラスのシグニチャでSタイプを省略して、インターフェイスにのみ含めることができます。

更新(2)

できることの1つは、Classプロパティのインターフェイスを作成することです。次のインターフェースを定義できます。

public interface IClass<T> where T : myType {
    // TODO
    // Define some interface definition, but you cannot use the
    // EntityObject derived class, since they are not to be known 
    // in the service class.      
}

このインターフェイスをClassBaseクラスに実装し、タイプIClassのオブジェクトを受け入れるコンストラクターをServiceBaseクラスに追加すると、このオブジェクトを基本クラスのプロパティClassにプッシュできます。このような:

public abstract class ClassBase<T, S> : IClass<T>
    where T : MyType
    where S : EntityObject {
}

public abstract class ServiceBase<T> where T : MyType {
    protected ServiceBase(IClass<T> classObject) {
        Class = classObject;
    }
    protected IClass<T> Class { get; set; }
}

public class ServiceInherited : ServiceBase<MyTypeDerived> {
    public ServiceInherited(IClass<MyTypeDerived> classObject)
        : base(classObject) {
    }
}

注意すべきことの1つは、ClassBaseのSタイプをインターフェースに公開しないことです。Serviceクラスにこのタイプを認識させたくないため、メソッドをアクティブに呼び出したり、定義にSタイプが含まれているプロパティを使用したりすることはできません。

于 2012-12-04T13:25:03.607 に答える
1

この醜いボクシング、開梱はうまくいくはずです:

Class = (ClassBase<T, S>)(object)new ClassInherited();

共分散は、今日の汎用インターフェースでのみ許可されていますか?MSDN

これは動作します:

// Covariance. 
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument  
// is assigned to an object instantiated with a less derived type argument.  
// Assignment compatibility is preserved. 
IEnumerable<object> objects = strings;

これはしません:

 List<string> strings = new List<string>();
        List<object> objects = strings;
于 2012-12-04T15:25:30.807 に答える
0

コンパイラは、実行時のジェネリック型のインスタンス化で決定されるTSの正確な型を知らないため、 ClassAliExpressが実際にClassBase <T、S>に正しく一致することを推測できません。

したがって、実行時に型に互換性があることが確実な場合は、キャストを安全に試すことができます。

Class = ClassInheritedInstance as ClassBase<T, S>

CLRは安全なコードを取得するために型の互換性をチェックする必要があるため、これにはわずかな(無視できるとは言えない)オーバーヘッドしかありません。

于 2012-12-03T22:34:04.627 に答える