2017-11-19 3 views
-1

マイインターフェース(その一部):インターフェイスパラメータの制約

public interface IRepository 
{ 
    Task<T> Insert<T>(T item) where T : class, ISyncable; 
} 

私の実装:TableOperation.InsertITableEntityなどISyncable

する必要があるため

public class TableStorageRepository: IRepository 
{ 
    public async Task<T> Insert<T>(T item) where T: class, ISyncable 
    { 
     TableOperation.Insert(item); 
    } 
} 

私の実装では動作しません。

Task<T> Insert<T>(T item) where T : class, ISyncable, ITableEntity;私の他のIRepository実装が動作しないためe。

その後、制約は、次のエラーが発生しており、もはやインタフェースの制約と一致していないので、私はどちらか私の実装パラメータの制約にITableEntityを追加することはできません。

「パラメータの型の制約を「Tを'メソッドの...」

これを解決するためのエレガントな方法はありますか?

+1

別のインターフェイス/メソッドを作成できない場合は、実行時エラーが発生して生きていて、それを文書化してください –

+1

実行時に 'TableStorageReposity'で' item'の型をチェックし、渡されたオブジェクトが 'ITableEntity'を実装していない場合は' ArgumentException'を返します... – Michael

+0

ギャップを埋めることは可能でしょうか?実装の詳細を隠す?つまり、 'ISyncable'を実装しているクラスを受け入れ、その差を内部的に扱うということですか? –

答えて

0

IMHO設定が間違っています。あなたはLiskov substitution principleを破っています。

IRepositoryインターフェイスで契約が定義されています。この契約では、TISyncableで参照タイプがある限り、を挿入できます。

クラスTableStorageRepositoryは、その契約がであることを保証します。 ISyncableは処理できません。ITableEntityしか処理できません。それは生きていけないインターフェースを実装するビジネスを持っていないので、それをしないでください。

これは、乱雑なランタイムタイプのチェックなどで回避できますが、ハックの短いものではありません。あなたのビルディングブロックは悪いので、あなたがそれらの上に構築するものはすべて最高で薄れているでしょう。

特定の操作が有効であるかどうかを消費者に知らせるメソッドをインタフェースに定義することは、この場所にいることを避けることができない場合に有効な緩和戦略の1つです。bool CanInsert<T>しかし、これはオプションではありません。

+0

私はあなたがここでポイントを逃していると思う、私が言ったように:これは理想的だろう:タスクを挿入(Tアイテム)T:class、ISyncable、ITableEntity;しかし残念ながら、ITableEntityを追加することはできません。これは、他のリポジトリを破壊するためです。 TableStorageでは、まだISyncableが必要ですが、さらにITableEntityが必要です。私はCanInsertを追加することができましたが、私はむしろそうすることなくやりたいと思いました。私はインターフェースを変更できないとは決して言いませんでした。とにかく、洞察力/コメント/回答ありがとう! – Niels

+0

@Niels私はポイントを逃していません。クラスが本当に実装できないインターフェースを実装するように強制しようとしています。すべての 'ISyncable'が' ITableEntity'です。あなたが経験しているように、これは良い状況ではありませんし、タイプシステムがあなたを援助していない、あなたと戦っています。場合によっては、他の選択肢はありません。そのような場合は、通話が成功するかどうかを知るための方法をユーザーに提供することが最善の方法です([困惑させる]は避けてください)(https://blogs.msdn.microsoft。 com/ericlippert/2008/09/10/vexing-exceptions /): 'System.IO.Stream'は、' CanSeek'の古典的な例です。 – InBetween

+0

@Neils私は、ITableEntityが 'ISyncable'を実装していると信じているかもしれません。そうでなければ、あなたはさらに悪い状況に陥っています。 – InBetween