2011-12-19 10 views
0

非常に混乱している場合は、私のお詫び申し上げます。C#のジェネリックスを使用した相互依存インターフェイス

私はこの2つの主要なインターフェースを持っています。まずISensorインタフェース:

public interface ISensor<TReading> 
    where TReading : ISensorReading<ISensor<TReading>> 
{ 
    event SensorReadingCompletedEH<ISensor<TReading>, TReading> ReadCompleted; 
    TReading Read(); 
} 

そして、第2のインタフェース:ISensorReading

public interface ISensorReading<TSensor> 
    where TSensor : ISensor<ISensorReading<TSensor>> 
{ 
    TSensor Sensor { get; } 
} 

それは以下のエラーにつながる:>を踏む

タイプISENSOR <は
に変換可能でなければなりませんISensor < ISensorReading < ISensor < TReadingジェネリック型のパラメータTSensorとしてそれを使用するため、または方法において> > ISensorReading <TSensor>

タイプISensorReading <TSensor>は
ISensorReading < ISENSOR < ISensorReading < TSensorに変換可能でなければなりません> > >をパラメータとして使用する一般的なタイプまたはメソッドで使用するISensor <TReading>

コンパイル時に不明瞭な循環参照が原因であることが心配です。しかし私はTelemetricSensorのような派生型のための合同を確保したい:ISensor<TelemetricReading>と TelemetricReading:私は、単純なキャストと型安全を許可するために使用する他のaproaches

ISensorReading<TelemetricSensor>

私はあなたが、それは無限の入れ子につながるので、あなたは、ジェネリック型の制約をこのように使用してそれらを定義することはできません右です.NET 2.0とVS2005

答えて

0

ご回答いただきありがとうございます。

最後に、この問題を解決する方法を選択します。役に立つと願っています。コメントがある場合やフレームワークを変更せずにそれをimprioveする方法を知っている場合は、私に教えてください。

まず、最小限の要件でISensorインターフェイスを作成しました。定義と同じ構造を以下、私が最初の実装製にできたtheeseインターフェースで

public delegate void SensorErrorEventHandler<TSensor>(TSensor sensor, ISensorError error) 
    where TSensor : ISensor; 

public delegate void SensorReadingCompletedEventHandler<TSensor, TReading>(TSensor sensor, TReading[] read) 
    where TSensor : ISensor 
    where TReading : ISensorReading<TSensor>; 

public interface ISensor : IDisposable 
{ 
    bool IsOpen { get; } 
    bool Started { get; } 
    void Connect(); 
    void Disconnect(); 
    void Start(); 
    void Stop(); 
} 

public interface ISensor<TSensor, TReading> : ISensor 
    where TSensor : ISensor 
    where TReading : ISensorReading<TSensor> 
{ 
    TReading[] LastReadings { get; } 
    event SensorErrorEventHandler<TSensor> Error; 
    event SensorReadingCompletedEventHandler<TSensor, TReading> ReadCompleted; 
    bool Read(out TReading[] readings); 
} 

public interface ISensorReading<TSensor> where TSensor : ISensor 
{ 
    TSensor Sensor { get; } 
    bool Mistaken { get; } 
} 

:次のようにその後私は、新しいISENSOR汎用インターフェイスを定義そのcorrespondient ITelemetricReadingとTelemetricSensorクラス

public delegate void TelemetricSensorThresholdExceededEventHandler<TSensor>(TSensor sensor) 
    where TSensor : ITelemetricSensor; 

public interface ITelemetricSensor : ISensor 
{ 
    /* Properties, events and methods */ 
} 

public interface ITelemetricReading : ISensorReading<ITelemetricSensor> 
{ 
    /* Properties, events and methods */ 
} 

public abstract class TelemetricSensor<TSensor, TReading> : ITelemetricSensor, ISensor<TSensor, TReading> 
    where TSensor : ITelemetricSensor 
    where TReading : ITelemetricReading, ISensorReading<TSensor> 
{ 
    public abstract TReading[] LastReadings { get; } 
    public event SensorErrorEventHandler<TSensor> Error; 
    public event SensorReadingCompletedEventHandler<TSensor, TReading> ReadCompleted; 

    public abstract bool Read(out TReading[] readings); 
} 

ここでは、TelemetricSensorの抽象クラスを引き継ぐのは面白いです。 ITelemetricReadingがISensorReadingから継承するために冗長であるように見えるかもしれない

TReading : ITelemetricReading, ISensorReading<TSensor> 

として定義されるが、コードコンパイルを取得するために必要であり、両方

TReading[] LastReadings { get; } 

性及び

の要件を満たし
bool Read(out TReading[] readings); 

メソッド。最後に、退屈なキャスト(およびおそらく何らかのエラー)をスキップするために、Read(...)の複数のオーバーロードを実行して、それぞれが正しくキャストされたデータを提供し、すべてのインターフェイス実装を満たします。

1

を使用しています。あなたは何ができるか

は、例えば、1またはその他の具体的な実装を持っている。そして、

public interface ITelemetricSensorReading : ISensorReading 

とその実装を強制するためにセンサーを制約:

public interface ITelemetricSensor<TReading> : ISensor<TReading> where TReading : ITelemetricSensorReading 
1

言って、あなたはあなたの2種類を定義します:

class AReading : ISensorReading<ASensor> { } 
    class ASensor : ISensor<AReading> { } 

今、宣言ISensorReading<ASensor>ASensorISensor<ISensorReading<ASensor>>を実装していないため、不正です。代わりに、ISensor<Areading>が実装されています。

.NETでは、文A : Bは、通常、文I<A> : I<B>を意味しません。注意深く考えると、これは必ずしも真実ではありません。Iの性質に依存します。

あなたが探している機能は、「共分散」と「コントラバリエーション」と呼ばれています。それはC#の別の機能です。ここでは、あなたの特定のインターフェイスのために、上記の意味は実際には(共分散)を保持するか、逆の意味はI<B> : I<A>が保持する(contravariance)ことをコンパイラに伝えることができます。

あなたがoutキーワードを使用することによって達成最初の1:

interface I<out T> { ... } 

二 - inキーワードを使用して:ジェネリック型パラメータの

interface I<in T> { ... } 

しかし、残念ながら、共変性と反変性を持っていますC#4.0でしか導入されていないので、あなたはここで不運です。

C#4.0にアップグレードすることをお勧めします(強くお勧めします)。また、すべての種類の一貫性を保つために単体テストに頼ることもできます。

+0

実際には、共分散および反動が頭痛の原因となります。 残念ながら、私のアプリケーションはMONOとできるだけ互換性があり、C#4.0へのアップグレードはオプションではありません。また、.NET 4.0は.NET 2.0ほど効率的ではないことに気付きました – Kyordhel

+0

.net 4.0は2.0より効率が悪いですか?どのように、正確に? –

関連する問題