3

私が持っているとしましょう:

  • 一般的な方法Get<T>
  • いくつかのインターフェースIEntityIValue
  • これらのインターフェースをそれぞれ実装するいくつかのクラス ex: Entity-> IEntityValue->IValueなど。

=>Get<T>メソッドがインターフェイスをジェネリック型としてのみ許可する方法はありますか?

Get<IEntity>(42); //Allowed
Get<Entity>(42);  //Compiler error

私の現在のソリューションは次のようになります。

  • Get<T>Type 制約を持つジェネリック メソッドwhere T: IPersistable(ほとんどの型がパラメーターとして渡されないようにするため)
  • インターフェイスは実装しますIPersistable

関数はアクティブに型をチェックします。

public T Get<T>(long id) where T : IPersistable
{
   if (typeof (T) == typeof (IEntity))
      return (T) EntityDao.Get(id);
   if (typeof (T) == typeof (IValue))
      return (T) ValueDao.Get(id);

   //...

   throw new TechnicalException("Type not supported");
}

=> 問題は次のとおりです。

  1. それはきれいではありません...チェックするタイプが非常に少ないので、私はそれで暮らすことができました
  2. 署名は、関数が実際に行うことと一致しません。それはIPersistablein を許可しますが、実際には <- は許可しません。それは本当に私を悩ませます:(

編集:クラスの過剰人口を避けるために、そのような制約を検討しています。

そのクラスには、ほぼすべてこのように機能する 8 つまたは 9 つのジェネリック メソッドがあります。直感的な方法は、@DanielHilgarthがタイプごとに1つのメソッドのみを持つことを提案したことです。メソッドは現在、4 または 5 種類でのみ呼び出すことができます。それでも、それはそのクラスに 32 ~ 40 個のメソッドがあることを意味します。

できればそれは避けたいです。

Edit2 :「実際の」クラスが呼び出されるのを防ぐ必要性は、共分散/反分散の問題から生じます。EntityDaoおよびValueDaoGet<T>メソッドはオブジェクトを返します。でキャストできないため、メソッドでコレクションを呼び出すと、単一のオブジェクトを照会するとうまくいきません。IEntityIValueGetAll<T>IEnumerable<IValue>IEnumerable<Value>

リストのキャストに関する@JonSkeetsからのこの回答に気付きました。それは回避策かもしれません...

4

2 に答える 2

5

専用のメソッドを作成するだけです。のサンプル コードはif、現在のメソッドが 1 つのことを行っていないことを示しています。複数で行います。

ちょうど行く:

GetEntity(42);
GetValue(13);

public IEntity GetEntity(long id)
{
    return EntityDao.Get(id);
}

public IValue GetValue(long id)
{
    return ValueDao.Get(id);
}

これは、すべてのレイヤーでよりクリーンです。

  1. GetEntity対。Get<IEntity>
  2. 可能なことを明確に伝えます。ランタイム例外はありません。
  3. get メソッドは型の切り替えを必要としません。

これにより、サービスに同様のメソッドが多すぎる場合は、新しいクラス ( forEntityとfor など) を分割する必要がありValueます。次に、新しいクラスを返すサービス プロパティを指定できます。これは、クエリ オブジェクトを実装するときに行っていることと同じです。次に、次のようになりますservice.Values.Get(13)service.Entities.Get(42)

于 2013-01-29T10:02:51.567 に答える
1

これは別の方法かもしれません:

abstract class Persistable<T>
{
    protected static Func<long, T> mapFunction;
    public static T Get(long id)
    {
        return mapFunction(id);
    }
}

class Entity : Persistable<Entity>
{
    public static Entity()
    {
        Persistable<Entity>.mapFunction = input => EntityDao.Get(input);
    }
}
class Value : Persistable<Value>
{
    public static Value()
    {
        Persistable<Value>.mapFunction = input => ValueDao.Get(input);
    }
}

Getメソッドは次のようになります。

public T Get<T>(long id) // maybe you restrict the T to something
{
    Persistable<T>.Get(id);
}
于 2013-01-29T12:16:19.210 に答える