using System; using System.ComponentModel.Design; using System.Reflection; using Chernobyl.Collections.Generic.Event; using Chernobyl.Event; namespace Chernobyl.Dependency { /// /// Used to mark an instance as being "provided" to an /// instance. When this type has it's /// /// method invoked, it will add the instance to the /// instance provided. /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class ProvideAttribute : ServiceAttribute { /// /// Initializes a new instance of the /// class. /// public ProvideAttribute() { } /// /// Initializes a new instance of the /// class. /// /// The location of the service within the /// hierarchy or null if the service is at the /// root of the hierarchy. This array represents the /// "path" that must be taken through the hierarchy of /// to get to the location where the service /// specified by resides. Each /// must implement the /// interface. An example of what the service path might look like /// (using '/' as separators): /// /IEventCollection{T}/IGraphicsServices/ITextureServices /// In this example, the service represented by /// is located in the /// ITextureServices. That /// is located within IGraphicsServices which /// is located at the root . public ProvideAttribute(params Type[] location) : base(location) { } /// /// Adds the service specified by the /// to the instance. Note that the service /// is added as a so that the /// property is only invoked when the service is actually needed. /// /// The instance that /// allows access to the other services and provides adding or removing /// of specific services. /// The instance that contained a code element that /// was attributed with a instance. /// The code element that was attributed /// with a and whose service needs to be /// added into the . public override void Resolve(IEventCollection services, object instance, ICustomAttributeProvider attributeProvider) { _property = (PropertyInfo)attributeProvider; Type = Type ?? _property.PropertyType; _instance = instance; // If the service belongs at the root we'll just add it now. // Otherwise, we'll need to traverse down the IEventCollection{T} instance // till we find the IEventCollection{T} we need to add the service to. if (Location.Length != 0) services.OfType(Location[0], ServiceRetriever); else services.Add(CreateService()); } /// /// The method that is invoked when the service of the type specified by /// is resolved and can be used. /// /// The service that was requested. void ServiceRetriever(object service) { IEventCollection services = (IEventCollection)service; // If we we've reached the last Type in the location path // then we are at the IEventCollection{T} that we need to provide the service // to. Otherwise, continue down the IEventCollection{T} descendants until we // reach the IEventCollection{T} instance we need to add the service to. if (_currentLocationIndex == (Location.Length - 1)) services.Add(CreateService()); else { ++_currentLocationIndex; services.OfType(Location[_currentLocationIndex], ServiceRetriever); } } /// /// Creates the service and returns it. /// /// The service or null if the service could not be created. object CreateService() { return _property.GetValue(_instance, null); } /// /// The index into the array /// that points to the we are currently processing /// in . /// int _currentLocationIndex; /// /// The property that was attributed with this attribute. /// PropertyInfo _property; /// /// The instance that whose type was attributed with this attribute. /// object _instance; } }