summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/DependencyService.cs
blob: 2e0ae0568ec6affc3320fa9b8b3776c02ce8e41a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
´╗┐using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Xamarin.Forms
{
	public static class DependencyService
	{
		static bool s_initialized;

		static readonly List<Type> DependencyTypes = new List<Type>();
		static readonly Dictionary<Type, DependencyData> DependencyImplementations = new Dictionary<Type, DependencyData>();

		public static T Get<T>(DependencyFetchTarget fetchTarget = DependencyFetchTarget.GlobalInstance) where T : class
		{
			Initialize();

			Type targetType = typeof(T);

			if (!DependencyImplementations.ContainsKey(targetType))
			{
				Type implementor = FindImplementor(targetType);
				DependencyImplementations[targetType] = implementor != null ? new DependencyData { ImplementorType = implementor } : null;
			}

			DependencyData dependencyImplementation = DependencyImplementations[targetType];
			if (dependencyImplementation == null)
				return null;

			if (fetchTarget == DependencyFetchTarget.GlobalInstance)
			{
				if (dependencyImplementation.GlobalInstance == null)
				{
					dependencyImplementation.GlobalInstance = Activator.CreateInstance(dependencyImplementation.ImplementorType);
				}
				return (T)dependencyImplementation.GlobalInstance;
			}
			return (T)Activator.CreateInstance(dependencyImplementation.ImplementorType);
		}

		public static void Register<T>() where T : class
		{
			Type type = typeof(T);
			if (!DependencyTypes.Contains(type))
				DependencyTypes.Add(type);
		}

		public static void Register<T, TImpl>() where T : class where TImpl : class, T
		{
			Type targetType = typeof(T);
			Type implementorType = typeof(TImpl);
			if (!DependencyTypes.Contains(targetType))
				DependencyTypes.Add(targetType);

			DependencyImplementations[targetType] = new DependencyData { ImplementorType = implementorType };
		}

		static Type FindImplementor(Type target)
		{
			return DependencyTypes.FirstOrDefault(t => target.IsAssignableFrom(t));
		}

		static void Initialize()
		{
			if (s_initialized)
			{
				return;
			}

			Assembly[] assemblies = Device.GetAssemblies();
			if (Registrar.ExtraAssemblies != null)
			{
				assemblies = assemblies.Union(Registrar.ExtraAssemblies).ToArray();
			}

			Initialize(assemblies);
		}

		internal static void Initialize(Assembly[] assemblies)
		{
			if (s_initialized)
			{
				return;
			}

			Type targetAttrType = typeof(DependencyAttribute);

			// Don't use LINQ for performance reasons
			// Naive implementation can easily take over a second to run
			foreach (Assembly assembly in assemblies)
			{
				Attribute[] attributes = assembly.GetCustomAttributes(targetAttrType).ToArray();
				if (attributes.Length == 0)
					continue;

				foreach (DependencyAttribute attribute in attributes)
				{
					if (!DependencyTypes.Contains(attribute.Implementor))
					{
						DependencyTypes.Add(attribute.Implementor);
					}
				}
			}

			s_initialized = true;
		}

		class DependencyData
		{
			public object GlobalInstance { get; set; }

			public Type ImplementorType { get; set; }
		}
	}
}