2

データベース内の文字列値の実際の変換値への変換をメモ化するために使用する一般的な方法があります。

public MySpecialValue {
    object val;
    bool valSet = false; 

    T GetValue<T> () { 
         if (!valSet)
         {
                val = (T)Convert.ChangeType(DatabaseValue, typeof(T));
                valSet = true;
         }
         return (T)val;
     }

     public string DatabaseValue { get; set; }
}

問題は、初期化中にデータベース内のデータのタイプがわからないことです。この決定を行うことができるのは最初の呼び出しのみです。

キャッシュされている値の型をボックス化解除することを強制されないように構造化する方法はありますか? (包含クラスの署名を変更せずに)

4

5 に答える 5

5

あなたが与えるコードはやや奇妙です。「DoSomethingExpensive」は、任意の T に対して T を返すことをどのように知っていますか? それは私には意味がありません。

通常、一般的なメモライザーを作成する方法は次のとおりです。

public static Func<T> Memoize(this Func<T> func)
{
    bool executed = false;
    T result = default(T);
    Func<T> memoized = ()=> 
    {
        if (!executed)
        {
            result = func();
            executed = true;
        }
        return result;
    };
    return memoized;
}

そして今、あなたは言うことができます:

Func<int> expensive = DoSomethingExpensiveThatGetsAnInt;
Func<int> memoized = expensive.Memoize();

これで完了です。ボクシングは必要ありません。

于 2011-01-19T02:21:51.403 に答える
3

T と結果Convert.ChangeTypeが参照型の場合、ボックス化解除は行われません。

ボックス化された値の型を返し、T が値の型である場合Convert.ChangeType、GetValue に T を返させたい場合、ボックス化解除を回避するためにできることは何もありません。

于 2011-01-19T01:27:41.880 に答える
1

これに使用することを検討してくださいLazy<T>

したがって、ある種のプロパティのコレクションがある場合。

public class MyClass 
{
...
}

Public class MyClass<T> : MyClass
{
  T val;
  bool valSet; 
  public T GetValue<T> () { 
        if (!valSet)
        {
            val = (T)Convert.ChangeType(DatabaseValue, typeof(T))};
            valSet = true;
        }
        return val;
    }
}

おそらく、親クラスにジェネリックメソッドがあります

class SomePropertyBag{

private Dictionary<string, MyClass> dict;

T GetValue<T>(string name, T default)
{
  MyClass res;
  if(!dict.TryGetValue(out res))
  {
     res = new MyClass<T>(name);
     dict.Add(name, res);
  }
  return ((MyClass<T>)res).GetValue();
}
于 2011-01-19T01:32:26.120 に答える
1

ほとんどの場合、このコードは返信の例に従って呼び出されることに賭けます(OK、ソースコードを持っているという利点もあります...)。

Get("Site.Twitter.AccountName", "")

また

Get("Site.Twitter.AccountName", 77)

その場合、ジェネリック型推論を使用しています。しかし、そこにコンパイルされる別の、より単純なものがあります...ジェネリックを使用しないでください。ここにはいくつかのシナリオしかないと思います。そのため、いくつかのクラス/メソッドオーバーロードを作成stringします-1つは 用、もう1つは 用intなど。

string Get(string key, string defaultValue) {...}
int Get(string key, int defaultValue) {...}
bool Get(string key, bool defaultValue) {...}

確かに、多少の重複はありますが、コンパイラは個々のシナリオごとに最適化できます。ボクシングは不要です。(選択した場合)を(場合によって)のConvert.ChangeTypeようなものに置き換えることもできます。int.ParseT = int


別のオプション(あなたの例を考えると)は、メモ化されたオブジェクトをジェネリックにすることです:

public MySpecialValue<T> {
    T val;
    bool valSet = false; 

    T GetValue() { 
         if (!valSet)
         {
                val = (T)Convert.ChangeType(DatabaseValue, typeof(T));
                valSet = true;
         }
         return val;
     }

     public string DatabaseValue { get; set; }
}

<T>コードをレベルアップして、キャストで実行します。

于 2011-01-19T06:07:54.923 に答える
0

これにより、値型 (ボックス化解除なし) の処理がわずかに速くなり、ref 型の呼び出しが 1 つ増えると、処理がわずかに遅くなります ... ただし、少し奇妙です。

 class MyClass {
    class Container<T>
    {
        public T Value { get; set; }
    }

    bool valSet;
    object val; 

    public T GetValue<T> () { 
        if (!valSet)
        {
            val = new Container<T>{Value =  (T)Convert.ChangeType(DatabaseValue, typeof(T))};
            valSet = true;
        }
        return ((Container<T>)val).Value;
    }

    public string DatabaseValue { get; set; }
 }
于 2011-01-19T02:28:23.710 に答える