1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Reflection; 12 13 namespace Antmicro.Renode.Core 14 { 15 public class ObjectCreator 16 { ObjectCreator()17 static ObjectCreator() 18 { 19 Instance = new ObjectCreator(); 20 } 21 22 public static ObjectCreator Instance { get; private set; } 23 OpenContext()24 public Context OpenContext() 25 { 26 var context = new Context(this); 27 contexts.Push(context); 28 return context; 29 } 30 Spawn(Type type, Func<ParameterInfo, object> argumentResolver = null)31 public object Spawn(Type type, Func<ParameterInfo, object> argumentResolver = null) 32 { 33 foreach(var constructor in type.GetConstructors()) 34 { 35 var @params = constructor.GetParameters(); 36 var args = new object[@params.Length]; 37 var success = true; 38 for(int i = 0; i < args.Length; i++) 39 { 40 var surrogate = GetSurrogate(@params[i].ParameterType); 41 if(surrogate == null) 42 { 43 if(argumentResolver != null) 44 { 45 surrogate = argumentResolver(@params[i]); 46 } 47 } 48 if(surrogate == null) 49 { 50 success = false; 51 break; 52 } 53 54 args[i] = surrogate; 55 } 56 57 // try next constructor 58 if(!success) 59 { 60 continue; 61 } 62 63 return Activator.CreateInstance(type, args); 64 } 65 66 // if no constructor was matched, throw exception 67 throw new ArgumentException(string.Format("Couldn't spawn object of type: {0}\nAvailable surrogate types are:\n{1}", type.FullName, 68 string.Join("\n", contexts.SelectMany(x => x.Types).Distinct().Select(x => x.FullName)))); 69 } 70 GetSurrogate()71 public T GetSurrogate<T>() 72 { 73 return (T)GetSurrogate(typeof(T)); 74 } 75 GetSurrogate(Type type)76 public object GetSurrogate(Type type) 77 { 78 return contexts.Select(x => x.GetSurrogate(type)).FirstOrDefault(x => x != null); 79 } 80 GetSurrogate(string typeName)81 public object GetSurrogate(string typeName) 82 { 83 return contexts.Select(x => x.GetSurrogate(typeName)).FirstOrDefault(x => x != null); 84 } 85 ObjectCreator()86 protected ObjectCreator() 87 { 88 contexts = new Stack<Context>(); 89 } 90 CloseContext(Context context)91 private void CloseContext(Context context) 92 { 93 if(context != contexts.Peek()) 94 { 95 throw new ArgumentException(); 96 } 97 98 contexts.Pop(); 99 } 100 101 private readonly Stack<Context> contexts; 102 103 public class Context : IDisposable 104 { Context(ObjectCreator creator)105 public Context(ObjectCreator creator) 106 { 107 objectCreator = creator; 108 surrogates = new Dictionary<Type, object>(); 109 } 110 RegisterSurrogate(Type type, object obj)111 public void RegisterSurrogate(Type type, object obj) 112 { 113 surrogates.Add(type, obj); 114 } 115 GetSurrogate(Type type)116 public object GetSurrogate(Type type) 117 { 118 object result; 119 surrogates.TryGetValue(type, out result); 120 return result; 121 } 122 GetSurrogate(string typeName)123 public object GetSurrogate(string typeName) 124 { 125 return surrogates.FirstOrDefault(x => x.Key.FullName.Contains(typeName)).Value; 126 } 127 Close()128 public void Close() 129 { 130 objectCreator.CloseContext(this); 131 } 132 Dispose()133 public void Dispose() 134 { 135 Close(); 136 } 137 138 public IEnumerable<Type> Types { get { return surrogates.Keys; } } 139 140 private readonly ObjectCreator objectCreator; 141 private readonly Dictionary<Type, object> surrogates; 142 } 143 } 144 } 145 146