You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,301 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="ServiceObjectContainer.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
*/
|
||||
namespace System.ComponentModel.Design {
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Permissions;
|
||||
|
||||
/// <devdoc>
|
||||
/// This is a simple implementation of IServiceContainer.
|
||||
/// </devdoc>
|
||||
[HostProtection(SharedState = true)]
|
||||
public class ServiceContainer : IServiceContainer, IDisposable
|
||||
{
|
||||
private ServiceCollection<object> services;
|
||||
private IServiceProvider parentProvider;
|
||||
private static Type[] _defaultServices = new Type[] { typeof(IServiceContainer), typeof(ServiceContainer) };
|
||||
|
||||
private static TraceSwitch TRACESERVICE = new TraceSwitch("TRACESERVICE", "ServiceProvider: Trace service provider requests.");
|
||||
|
||||
/// <devdoc>
|
||||
/// Creates a new service object container.
|
||||
/// </devdoc>
|
||||
public ServiceContainer() {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Creates a new service object container.
|
||||
/// </devdoc>
|
||||
public ServiceContainer(IServiceProvider parentProvider) {
|
||||
this.parentProvider = parentProvider;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Retrieves the parent service container, or null
|
||||
/// if there is no parent container.
|
||||
/// </devdoc>
|
||||
private IServiceContainer Container {
|
||||
get {
|
||||
IServiceContainer container = null;
|
||||
if (parentProvider != null) {
|
||||
container = (IServiceContainer)parentProvider.GetService(typeof(IServiceContainer));
|
||||
}
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// This property returns the default services that are implemented directly on this IServiceContainer.
|
||||
/// the default implementation of this property is to return the IServiceContainer and ServiceContainer
|
||||
/// types. You may override this proeprty and return your own types, modifying the default behavior
|
||||
/// of GetService.
|
||||
/// </devdoc>
|
||||
protected virtual Type[] DefaultServices {
|
||||
get {
|
||||
return _defaultServices;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Our collection of services. The service collection is demand
|
||||
/// created here.
|
||||
/// </devdoc>
|
||||
private ServiceCollection<object> Services {
|
||||
get {
|
||||
if (services == null) {
|
||||
services = new ServiceCollection<object>();
|
||||
}
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Adds the given service to the service container.
|
||||
/// </devdoc>
|
||||
public void AddService(Type serviceType, object serviceInstance) {
|
||||
AddService(serviceType, serviceInstance, false);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Adds the given service to the service container.
|
||||
/// </devdoc>
|
||||
public virtual void AddService(Type serviceType, object serviceInstance, bool promote) {
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Adding service (instance) " + serviceType.Name + ". Promoting: " + promote.ToString());
|
||||
if (promote) {
|
||||
IServiceContainer container = Container;
|
||||
if (container != null) {
|
||||
Debug.Indent();
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Promoting to container");
|
||||
Debug.Unindent();
|
||||
container.AddService(serviceType, serviceInstance, promote);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We're going to add this locally. Ensure that the service instance
|
||||
// is correct.
|
||||
//
|
||||
if (serviceType == null) throw new ArgumentNullException("serviceType");
|
||||
if (serviceInstance == null) throw new ArgumentNullException("serviceInstance");
|
||||
if (!(serviceInstance is ServiceCreatorCallback) && !serviceInstance.GetType().IsCOMObject && !serviceType.IsAssignableFrom(serviceInstance.GetType())) {
|
||||
throw new ArgumentException(SR.GetString(SR.ErrorInvalidServiceInstance, serviceType.FullName));
|
||||
}
|
||||
|
||||
if (Services.ContainsKey(serviceType)) {
|
||||
throw new ArgumentException(SR.GetString(SR.ErrorServiceExists, serviceType.FullName), "serviceType");
|
||||
}
|
||||
|
||||
Services[serviceType] = serviceInstance;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Adds the given service to the service container.
|
||||
/// </devdoc>
|
||||
public void AddService(Type serviceType, ServiceCreatorCallback callback) {
|
||||
AddService(serviceType, callback, false);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Adds the given service to the service container.
|
||||
/// </devdoc>
|
||||
public virtual void AddService(Type serviceType, ServiceCreatorCallback callback, bool promote) {
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Adding service (callback) " + serviceType.Name + ". Promoting: " + promote.ToString());
|
||||
if (promote) {
|
||||
IServiceContainer container = Container;
|
||||
if (container != null) {
|
||||
Debug.Indent();
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Promoting to container");
|
||||
Debug.Unindent();
|
||||
container.AddService(serviceType, callback, promote);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We're going to add this locally. Ensure that the service instance
|
||||
// is correct.
|
||||
//
|
||||
if (serviceType == null) throw new ArgumentNullException("serviceType");
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
|
||||
if (Services.ContainsKey(serviceType)) {
|
||||
throw new ArgumentException(SR.GetString(SR.ErrorServiceExists, serviceType.FullName), "serviceType");
|
||||
}
|
||||
|
||||
Services[serviceType] = callback;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Disposes this service container. This also walks all instantiated services within the container
|
||||
/// and disposes any that implement IDisposable, and clears the service list.
|
||||
/// </devdoc>
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Disposes this service container. This also walks all instantiated services within the container
|
||||
/// and disposes any that implement IDisposable, and clears the service list.
|
||||
/// </devdoc>
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
ServiceCollection<object> serviceCollection = services;
|
||||
services = null;
|
||||
if (serviceCollection != null) {
|
||||
foreach(object o in serviceCollection.Values) {
|
||||
if (o is IDisposable) {
|
||||
((IDisposable)o).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Retrieves the requested service.
|
||||
/// </devdoc>
|
||||
public virtual object GetService(Type serviceType) {
|
||||
object service = null;
|
||||
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Searching for service " + serviceType.Name);
|
||||
Debug.Indent();
|
||||
|
||||
// Try locally. We first test for services we
|
||||
// implement and then look in our service collection.
|
||||
//
|
||||
Type[] defaults = DefaultServices;
|
||||
for (int idx = 0; idx < defaults.Length; idx++) {
|
||||
if (serviceType.IsEquivalentTo(defaults[idx])) {
|
||||
service = this;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (service == null) {
|
||||
Services.TryGetValue(serviceType, out service);
|
||||
}
|
||||
|
||||
// Is the service a creator delegate?
|
||||
//
|
||||
if (service is ServiceCreatorCallback) {
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Encountered a callback. Invoking it");
|
||||
service = ((ServiceCreatorCallback)service)(this, serviceType);
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Callback return object: " + (service == null ? "(null)" : service.ToString()));
|
||||
if (service != null && !service.GetType().IsCOMObject && !serviceType.IsAssignableFrom(service.GetType())) {
|
||||
// Callback passed us a bad service. NULL it, rather than throwing an exception.
|
||||
// Callers here do not need to be prepared to handle bad callback implemetations.
|
||||
Debug.Fail("Object " + service.GetType().Name + " was returned from a service creator callback but it does not implement the registered type of " + serviceType.Name);
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "**** Object does not implement service interface");
|
||||
service = null;
|
||||
}
|
||||
|
||||
// And replace the callback with our new service.
|
||||
//
|
||||
Services[serviceType] = service;
|
||||
}
|
||||
|
||||
if (service == null && parentProvider != null) {
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Service unresolved. Trying parent");
|
||||
service = parentProvider.GetService(serviceType);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (TRACESERVICE.TraceVerbose && service == null) {
|
||||
Debug.WriteLine("******************************************");
|
||||
Debug.WriteLine("FAILED to resolve service " + serviceType.Name);
|
||||
Debug.WriteLine("AT: " + Environment.StackTrace);
|
||||
Debug.WriteLine("******************************************");
|
||||
}
|
||||
#endif
|
||||
Debug.Unindent();
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Removes the given service type from the service container.
|
||||
/// </devdoc>
|
||||
public void RemoveService(Type serviceType) {
|
||||
RemoveService(serviceType, false);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Removes the given service type from the service container.
|
||||
/// </devdoc>
|
||||
public virtual void RemoveService(Type serviceType, bool promote) {
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Removing service: " + serviceType.Name + ", Promote: " + promote.ToString());
|
||||
if (promote) {
|
||||
IServiceContainer container = Container;
|
||||
if (container != null) {
|
||||
Debug.Indent();
|
||||
Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Invoking parent container");
|
||||
Debug.Unindent();
|
||||
container.RemoveService(serviceType, promote);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We're going to remove this from our local list.
|
||||
//
|
||||
if (serviceType == null) throw new ArgumentNullException("serviceType");
|
||||
Services.Remove(serviceType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this collection to store mapping from the Type of a service to the object that provides it in a way
|
||||
/// that is aware of embedded types. The comparer for this collection will call Type.IsEquivalentTo(...)
|
||||
/// instead of doing a reference comparison which will fail in type embedding scenarios. To speed the lookup
|
||||
/// performance we will use hash code of Type.FullName.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
private sealed class ServiceCollection<T> : Dictionary<Type, T> {
|
||||
static EmbeddedTypeAwareTypeComparer serviceTypeComparer = new EmbeddedTypeAwareTypeComparer();
|
||||
|
||||
private sealed class EmbeddedTypeAwareTypeComparer : IEqualityComparer<Type> {
|
||||
#region IEqualityComparer<Type> Members
|
||||
|
||||
public bool Equals(Type x, Type y) {
|
||||
return x.IsEquivalentTo(y);
|
||||
}
|
||||
|
||||
public int GetHashCode(Type obj) {
|
||||
return obj.FullName.GetHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public ServiceCollection() : base(serviceTypeComparer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user