2013-01-24 33 views
5

Tôi đang sử dụng Ninject để nhanh chóng một số đối tượng với một arg constructor trôi qua, ví dụ:Instances Ninject Memoize trong Singleton Phạm vi

class MyClass 
{ 
    public MyClass(string myArg) 
    { 
     this.myArg = myArg; 
    } 
} 

Số trường hợp tôi cần của lớp này sẽ không được biết cho đến khi thời gian chạy, nhưng những gì tôi muốn làm là đảm bảo rằng mỗi biến thể của myArg kết quả trong một cá thể singleton khác nhau (do đó yêu cầu cùng một giá trị hai lần trả về cùng một cá thể, nhưng các arg khác nhau trả về các cá thể khác nhau).

Có ai biết cách tốt nhất, được tích hợp sẵn, cách thực hiện việc này không?

Tôi đã tìm thấy một bài viết được viết cho phiên bản cũ hơn của Ninject How To Ensure One Instance per Variation of Activation Parameters nhưng hy vọng sẽ có một giải pháp gọn gàng hơn cho phiên bản mới hơn.

Sửa

Dưới đây là những gì tôi đã đi với, chuyển thể từ câu trả lời Akim của dưới đây:

private readonly ConcurrentBag<string> scopeParameters = new ConcurrentBag<string>(); 

internal object ParameterScope(IContext context, string parameterName) 
{ 
    var param = context.Parameters.First(p => p.Name.Equals(parameterName)); 
    var paramValue = param.GetValue(context, context.Request.Target) as string; 
    paramValue = string.Intern(paramValue); 

    if (paramValue != null && !scopeParameters.Contains(paramValue)) 
    { 
     scopeParameters.Add(paramValue); 
    } 

    return paramValue; 
} 

public override void Load() 
{ 
    Bind<MyClass>() 
      .ToSelf() 
      .InScope(c => ParameterScope(c, "myArg")); 

    Bind<IMyClassFactory>() 
     .ToFactory(); 
} 
+0

Kiểm tra [ 'ninject.extensions.factory'] (https://github.com/ninject/ninject.extensions.factory) cho thực hiện tự động của nhà máy trừu tượng – Akim

Trả lời

3

Bạn có thể đạt được yêu cầu hành vi bằng cách cung cấp phạm vi tùy chỉnh sử dụng IBindingNamedWithOrOnSyntax<T> InScope(Func<IContext, object> scope) phương pháp MyClass ràng buộc

Cho biết rằng các trường hợp được kích hoạt thông qua các ràng buộc nên được tái u sed miễn là đối tượng được trả về bởi cuộc gọi lại được cung cấp vẫn còn sống (nghĩa là, chưa được thu gom rác).

Vì vậy, bạn cần trả về giá trị của đối số hàm tạo đầu tiên từ Func<IContext, object> scope và đảm bảo rằng sẽ không thu thập.

Dưới đây là một đoạn trích:

public class Module : NinjectModule 
{ 
    // stores string myArg to protect from CG 
    ConcurrentBag<string> ParamSet = new ConcurrentBag<string>(); 

    public override void Load() 
    { 
     Bind<MyClass>() 
      .ToSelf() 
      // custom scope 
      .InScope((context) => 
       { 
        // get first constructor argument 
        var param = context.Parameters.First().GetValue(context, context.Request.Target) as string;      

        // retrieves system reference to string 
        param = string.Intern(param); 

        // protect value from CG 
        if(param != null && ParamSet.Contains(param)) 
        { 
         // protect from GC 
         ParamSet.Add(param); 
        } 

        // make Ninject to return same instance for this argument 
        return param; 
       }); 
    } 
} 

ps: full sample code with unittests

+0

Thực sự thích giải pháp này đơn giản như thế nào, và tôi có thêm một chút trợ giúp trên wiki tại https://github.com/ninject/ninject/wiki/Object-Scopes. Các trường hợp sẽ cần phải đến từ một nhà máy mặc dù, bạn có biết nếu điều này sẽ tương thích với phần mở rộng nhà máy? Tôi cho rằng nó sẽ như thế. –

+0

Chắc chắn nó hoạt động! Xem [mẫu được cập nhật với 'ninject.extensions.facotry'] (https://gist.github.com/4622557) – Akim

+0

Tôi đã làm rõ ví dụ của bạn một chút trong mã của tôi để tôi có thể cho biết thông số nào cần sử dụng thay vì luôn bằng cách sử dụng đầu tiên và tôi đã viết một số xét nghiệm. Hoạt động hoàn hảo, cảm ơn !! –

Các vấn đề liên quan