5

現在、VaryByCustom機能をインターフェイスを実装するクラスに実装していますIOutputCacheVaryByCustom

public interface IOutputCacheVaryByCustom
{
    string CacheKey { get; }
    HttpContext Context { get; }
}

このインターフェイスを実装するクラスにはいくつかの規則があり、クラスの名前は「OutputCacheVaryBy_______」になります。ここで、空白はページのvaryByCustomプロパティから渡される値です。もう1つの規則は、コンストラクターの挿入によってコンテキストが設定されるというものです。

現在、私はこれを列挙型と次のようなswitchステートメントに基づいています

public override string GetVaryByCustomString(HttpContext context, 
                                              string varyByCustomTypeArg)
{
    //for a POST request (postback) force to return back a non cached output
    if (context.Request.RequestType.Equals("POST"))
    {
        return "post" + DateTime.Now.Ticks;
    }
    var varyByCustomType = EnumerationParser.Parse<VaryByCustomType?>
                            (varyByCustomTypeArg).GetValueOrDefault();


    IOutputCacheVaryByCustom varyByCustom;
    switch (varyByCustomType)
    {
        case VaryByCustomType.IsAuthenticated:
            varyByCustom = new OutputCacheVaryByIsAuthenticated(context);
            break;
        case VaryByCustomType.Roles:
            varyByCustom = new OutputCacheVaryByRoles(context);
            break;
        default:
            throw new ArgumentOutOfRangeException("varyByCustomTypeArg");
    }

    return context.Request.Url.Scheme + varyByCustom.CacheKey;
}

OutputCacheVaryBy + varyByCustomTypeArgクラスがであり、コンストラクター引数が唯一であることが常にわかっているのでcontext、elseブロックの場合、これを美化する必要はなく、自分のオブジェクトを。でインスタンス化できることに気付きましたActivator

そうは言っても、リフレクションは私の強みではなく、Activator静的な作成やオブジェクトを生成する他の方法に比べてかなり遅いことを私は知っています。この現在のコードに固執する必要がある理由はありますActivatorか、それともオブジェクトを作成するためにまたは同様の方法を使用する必要がありますか?

ブログhttp://www.smelser.net/blog/post/2010/03/05/When-Activator-is-just-to-slow.aspxを見たことがありますが、これがどのように適用されるかはよくわかりません。静的Tではなく実行時に型を操作しているためです。

4

6 に答える 6

6

反射が遅すぎる場合。おそらく、独自のObjectFactoryを機能させることができます。本当に簡単です。インターフェイスに新しいメソッドを追加するだけです。

    public interface IOutputCacheVaryByCustom
    {
        string CacheKey { get; }
        IOutputCacheVaryByCustom NewObject();
    }

オブジェクトテンプレートを保持する静的な読み取り専用のCloneDictionaryを作成するよりも。

    static readonly
        Dictionary<VaryByCustomType, IOutputCacheVaryByCustom> cloneDictionary
        = new Dictionary<VaryByCustomType, IOutputCacheVaryByCustom>
        {
            {VaryByCustomType.IsAuthenticated, new OutputCacheVaryByIsAuthenticated{}},
            {VaryByCustomType.Roles, new OutputCacheVaryByRoles{}},
        };

それが終わったら、辞書でテンプレートを選択してNewObject()を呼び出すために、すでに持っている列挙型を使用できます。

        IOutputCacheVaryByCustom result = 
             cloneDictionary[VaryByCustomType.IsAuthenticated].NewObject();

とても簡単です。実装する必要のあるNewObject()メソッドは、オブジェクトを直接作成することで新しいインスタンスを返します。

    public class OutputCacheVaryByIsAuthenticated: IOutputCacheVaryByCustom
    {
        public IOutputCacheVaryByCustom NewObject() 
        {
            return new OutputCacheVaryByIsAuthenticated(); 
        }
    }

必要なのはそれだけです。そして、それは信じられないほど速いです。

于 2010-09-10T05:23:10.813 に答える
4

リフレクションは可能な値のセットがかなり限られているため、実際にリフレクションを使用する必要はありません。しかし、あなたはこのようなことをすることができます

internal class Factory<T,Arg>
{
   Dictionary<string,Func<Arg.T>> _creators;
   public Factory(IDictionary<string,Func<Arg,T>> creators)
  {
     _creators = creators;
  }
}

作成ロジックを次のように置き換えます

_factory[varyByCustomTypeArg](context);

それはスイッチほど速くはありませんが、それは構造を維持し、うまく別々に使用します

于 2010-09-10T23:05:45.997 に答える
3

オブジェクトの作成を他の人に任せてもらうのが本当に好きです。たとえば、インターフェイスのさまざまな具体的な実装が必要な場合、IoCコンテナは私にとって不思議に機能しました。

Unityを使用した簡単な例として、次のような実装にキーをリンクする構成部分があります。

public void Register(IUnityContainer container)
{
   container.RegisterType<IOutputCacheVaryByCustom,OutputCacheVaryByIsAuthenticated>("auth");
   container.RegisterType<IOutputCacheVaryByCustom,OutputCacheVaryByRoles>("roles");
}

そして、あなたの作成は次のようにはるかに単純に見えます:

//injected in some form
private readonly IUnityContainer _container;

public override string GetVaryByCustomString(HttpContext context, 
                                              string varyByCustomTypeArg)
{
    //for a POST request (postback) force to return back a non cached output
    if (context.Request.RequestType.Equals("POST"))
    {
        return "post" + DateTime.Now.Ticks;
    }
    try
    {
    IOutputCacheVaryByCustom varyByCustom = _container.Resolve<IOutputCacheVaryByCustom>(varyByCustomTypeArg, new DependencyOverride<HttpContext>(context));
    }
    catch(Exception exc)
    {
       throw new ArgumentOutOfRangeException("varyByCustomTypeArg", exc);
    }
    return context.Request.Url.Scheme + varyByCustom.CacheKey;
}

または、IoCがオプションでない場合は、ファクトリに具象クラスを作成させるので、実際のメソッドについて心配する必要はありません。

于 2010-09-10T00:00:15.417 に答える
1

switchステートメントにとどまります。このような可能性のあるケースが2つしかない場合は、巧妙な抽象化を使用して、座ってプログラムの難しい部分を機能させないようにしようとしています...

そうは言っても、あなたの質問から、それを使用することはあなたのActivatorために働くかもしれないようです。テストしましたか?本当に遅すぎましたか?

または、ファクトリメソッドの束をに保持することもできますDictionary<string, Func<IOutputCacheVaryByCustom>。これらのオブジェクトを頻繁に(ループで)作成する場合は、これを使用します。string次に、キーを最適化enumして変換を実行することもできます。より抽象化すると、このコードの意図が隠されてしまいます...

于 2010-09-14T12:41:58.973 に答える
0

反射を使用します。

    public override string GetVaryByCustomString(HttpContext context,   
                                          string varyByCustomTypeArg)
    {
        //for a POST request (postback) force to return back a non cached output   
        if (context.Request.RequestType.Equals("POST"))   
        {   
            return "post" + DateTime.Now.Ticks;   
        }

        Type type = Type.GetType("OutputCacheVaryBy" + varyByCustomTypeArg, false)
        if (type == null)
        {
            Console.WriteLine("Failed to find a cache of type " + varyByCustomTypeArg);
            return null;
        }

        var cache = (IOutputCacheVaryByCustom)Activator.CreateInstance(type, new object[]{context});
        return context.Request.Url.Scheme + cache.CacheKey;
    } 

typenameの前に名前空間「My.Name.Space.OutputCacheVaryBy」を付ける必要がある場合があります。それでも問題が解決しない場合は、アセンブリ修飾名を試してください。

Type.GetType("Name.Space.OutputCacheVaryBy" + varyByCustomTypeArg + ", AssemblyName", false)
于 2010-09-14T12:52:03.853 に答える
0

新しいオブジェクトを作成する例を次に示します

public static object OBJRet(Type vClasseType)
{
    return typeof(cFunctions).GetMethod("ObjectReturner2").MakeGenericMethod(vClasseType).Invoke(null, new object[] { });
}

public static object ObjectReturner2<T>() where T : new()
{
    return new T();
}

いくつかの情報:

  • cFunctionsは、関数を含む静的クラスの名前です

また、クラスを配列リストに含める例:

    public static object OBJRet(Type vClasseType, ArrayList tArray, int vIndex)
    {
        return typeof(cFunctions).GetMethod("ObjectReturner").MakeGenericMethod(vClasseType).Invoke(null, new object[] { tArray, vIndex });
    }

    public static object ObjectReturner<T>(ArrayList tArray, int vIndex) where T : new()
    {
        return tArray[vIndex];
    }
于 2010-08-27T17:43:27.080 に答える