10

次のような汎用シングルトンがあります。

public class Cache<T>
{
    private Dictionary<Guid, T> cachedBlocks;

    // Constructors and stuff, to mention this is a singleton

    public T GetCache(Guid id)
    {
        if (!cachedBlocks.ContainsKey(id))
            cachedBlocks.Add(id, LoadFromSharePoint(id))
        return cachedBlocks[id];
    }

    public T LoadFromSharePoint(Guid id)
    {
        return new T(id)    // Here is the problem.
    }
}

エラーメッセージは次のとおりです。

new() 制約がないため、タイプ T のインスタンスを作成できません。

そのパラメーターを渡す必要idがあり、それ以外の方法はありません。これを解決する方法についてのアイデアは大歓迎です。

4

3 に答える 3

21

T通常、型をデフォルトのコンストラクターを持つ型に制約し、それを呼び出します。id次に、メソッドまたはプロパティを追加して、インスタンスに値を提供できるようにする必要があります。

public static T LoadFromSharePoint<T>(Guid id)
    where T : new()     // <-- Constrain to types with a default constructor
{
    T value = new T();
    value.ID = id;
    return value;
}

または、コンストラクターを介してパラメーターを提供する必要があることを指定しているidため、リフレクションを使用してパラメーター化されたコンストラクターを呼び出すことができます。呼び出すコンストラクタが型で定義されていることを確認する必要がありますTジェネリック型を、既定のコンストラクター以外の特定のコンストラクターを持つ型に制約することはできません。(例:where T : new(Guid)動作しません。)

たとえば、次のように呼び出すことができるコンストラクターonがあることを知っています。new List<string>(int capacity)List<T>

var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);

Tもちろん、後でキャスト ( to ) を実行したい場合もあります。

于 2013-02-21T13:13:36.717 に答える
5

これを行うには、何Tであるかを指定する必要があります。あなたCache<T>は何かを保持することができますか?TigerFridgeそしてint同様に?それはサウンドデザインではありません。拘束すべきです。インスタンスを構築するTために を受け取るインスタンスが必要です。GuidそれはジェネリックではありませんT。その非常に具体的なT. コードを次のように変更します。

public class Cache<T> where T : Cacheable, new()
{
    private Dictionary<Guid, T> cachedBlocks;

    // Constructors and stuff, to mention this is a singleton

    public T GetCache(Guid id)
    {
        if (!cachedBlocks.ContainsKey(id))
            cachedBlocks.Add(id, LoadFromSharePoint(id))
        return cachedBlocks[id];

       //you're first checking for presence, and then adding to it
       //which does the same checking again, and then returns the
       //value of key again which will have to see for it again. 
       //Instead if its ok you can directly return

       //return cachedBlocks[id] = LoadFromSharePoint(id);

       //if your LoadFromSharePoint is not that expensive.
       //mind you this is little different from your original 
       //approach as to what it does.
    }

    public T LoadFromSharePoint(Guid id)
    {
        return new T { Key = id };    // Here is no more problem.
    }
}

public interface Cacheable
{
    Guid Key { get; set; }
}

インターフェイスからすべてのキャッシュ可能オブジェクト (T渡されるものは何でもCache<T>) を取得しますCacheable

于 2013-02-21T13:26:46.037 に答える