كيفية اكتشاف نوع التنفيذ الأساسي للمثيل المزخرف عند استدعاء GetAllInstances؟

StackOverflow https://stackoverflow.com/questions/19825921

سؤال

لدي هذا الرمز:

using (container.BeginLifetimeScope())
{
    RenderWord instruction = new RenderWord();
    var instances = container.GetAllInstances<IInstructionHandler<RenderWord>>();
    var firstInstance = result.First();
}

instances هو من النوع IEnumerable<IInstructionHandler<RenderWord>>

firstInstance هو من النوع IInstructionHandler<RenderWord> وهذا في الواقع مثال لمصمم ديكور يزين مصمم ديكور آخر يزين مصمم ديكور آخر ...

في وقت التشغيل الطبقة الفعلية instances هو من النوع ContainerControlledCollection<IInstructionHandler<RenderWord>> وهذا ContainerControlledCollection يحتوي الفصل على معلومات مفيدة جدًا - الجزء الأساسي ImplementationType.

هل هناك أي طريقة بالنسبة لي للوصول إلى ContainerControlledCollection أو ال producers[0].Value.ImplementationType في وقت التشغيل لأنني أرغب حقًا في أن أتمكن من اكتشاف نوع التنفيذ الأساسي ضمن سلسلة أدوات الديكور.

هل كانت مفيدة؟

المحلول

أعتقد أن @atomaras قد يكون لديه نقطة جيدة بشأن تجريدك، على الرغم من أنني أعتقد أنه سيكون من الجيد أن تستخدم هذه المعلومات فقط داخل جذر التركيب الخاص بك، نظرًا لأن جذر التركيب الخاص بك على علم بالفعل بكل تطبيق في النظام.

أعتقد أن هناك عدة طرق للوصول إلى هذه المعلومات:

  1. استخدم ال DecoratorPredicateContext المعلومات التي يتم توفيرها إلى RegisterDecorator طريقة التمديد:

    var typeMapping = new Dictionary<Type, Type>();
    
    container.RegisterDecorator(typeof(IInstructionHandler<>), typeof(FakeDecorator<>), c =>
    {
        typeMapping[c.ServiceType]  = c.ImplementationType;
        // or perhaps even use c.AppliedDecorators property to see which decorators 
        // are applied.
    
        // return false to prevent the decorator from being applied.
        return false;
    });
    

    يمكنك إجراء تسجيل مزيف سيطلبه Simple Injector لكل منهما IInstructionHandler<T> في النظام، ولكنك تمنع تطبيقه عن طريق توفير مسند سيعود دائمًا false.يمكنك استخدام المعلومات التي يوفرها Simple Injector في ملف DecoratorPredicateContext لمعرفة نوع التنفيذ الفعلي.

بدلا من ذلك، يمكنك حقن DecoratorContext مثيل (الإصدار 2.6 وما فوق) في أعلى مصمم الديكور (كما هو موضح هنا).ال DecoratorContext يحتوي على نفس المعلومات الموجودة في DecoratorPredicateContext يفعل ذلك، ولكن سيتم حقن هذا الكائن تلقائيًا بواسطة Simple Injector في مصمم الديكور الذي يعتمد عليه.فهو يسمح لك باتخاذ القرار داخل مصمم الديكور، وهو ما قد يكون مناسبًا جدًا لحالتك.

  1. أضف ان IDecorator التجريد للنظام للسماح بعبور سلسلة الديكور.

    من خلال السماح لكل مصمم ديكور بتنفيذ أ IDecorator واجهة تسمح بالوصول إلى الديكور (تمامًا كما حدث هنا) يمكنك اجتياز سلسلة الديكور والعثور على نوع التنفيذ الفعلي:

    public interface IDecorator
    {
        object Decoratee { get; }
    }
    
    public static class DecoratorHelpers
    {
        public static IEnumerable<object> GetDecoratorChain(IDecorator decorator)
        {
            while (decorator != null)
            {
                yield return decorator;
    
                decorator = decorator.Decoratee as IDecorator;
            }
        }
    }
    

    يمكنك تنفيذ الديكورات الخاصة بك باستخدام هذه الواجهة كما يلي:

    public class SomeDecorator<T> : IInstructionHandler<T>, IDecorator
    {
        private readonly IInstructionHandler<T> decoratee;
    
        public SomeDecorator(IInstructionHandler<T> decoratee)
        {
            this.decoratee = decoratee;
        }
    
        object IDecorator.Decoratee { get { return this.decoratee; } }
    }
    

    عند تطبيق هذه الواجهة على جميع مصممي الديكور لديك، ستتمكن من القيام بذلك:

     var implementationTypes =
         from handler in container.GetAllInstances<IInstructionHandler<RenderWord>>()
         let mostInnerDecorator =
             DecoratorHelpers.GetDecoratorChain(handler as IDecorator).LastOrDefault()
         let implementation = mostInnerDecorator != null ? mostInnerDecorator.Decoratee : handler
         select implementation.GetType()
    
  2. سجل قائمة Registration الحالات في واحدة من RegisterAll الزائد، منذ Registration يعرف الكائن عن نوع التنفيذ الفعلي.

  3. ولكن بدلاً من النقطة 3، يمكنك أيضًا استخدام قائمة أنواع التنفيذ التي استخدمتها لإنشاء تلك التسجيلات:

    typeMapping[serviceType] = implementationTypes;
    container.RegisterAll(serviceType, implementationTypes);
    

    سوف يقوم Simple Injector بحل التطبيقات المسجلة دائمًا بنفس الترتيب الذي تم تسجيلها به (وهذا مضمون).لذا، عندما تقوم بحل مجموعة من الأشياء، سيكون لديك بالفعل قائمة بالتطبيقات التي تم وضعها بنفس الترتيب.

نصائح أخرى

لماذا لا تتحقق فقط من نوع FirstInstance؟ ألا يعطيك هذا نوع التنفيذ الفعلي؟ يجب أن أقول على الرغم من أن حقيقة أنك تحتاج إلى معرفة نوع التنفيذ هي مؤشر جيد على مشاكل التجريد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top