EasyInjector

思考并回答以下问题:

  • 什么是依赖注入?有哪几种注入方式?
  • 为什么需要IOC容器?直接注入不行吗?
  • 自定义特性是什么原理?

引言

使用[Inject]标签,可以根据字段类型自动注入一些数据,方便调用类与类之间的成员和函数,避免重复获取组件。游戏开始只读取一次,就可以直到游戏关闭为止。

使用了自定义特性,首先阅读反射和特性

使用方法

新建XX类,需要挂到Hierarchy面板上任意一个物体。

举个例子,例如先挂到Canvas,需要注入A类。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class XX : MonoBehaviour
{
void Awake()
{
A a = GameObject.Find(“Canvas”).GetComponent< A >();
EasyInjector.Instance.AddInject(a);
}

void OnDestroy()
{
EasyInjector.Instance.RemoveInject<A>();
}
}

注意一点:必须要说到A类注入成功了,在Awake里面函数,但是如果切换场景时,那就必须要移除A类注入方式,在OnDestroy()函数里面,如果再切回来场景时发现之前注入A类,没有被注销的话,就会导致重复注入A类成功,就会出现其他未知BUG。

使用方式:

由于上面已经讲了如何注入和注销,如何使用首先必须要继承MonoInjected,单独写一个MonoInjected。
代码如下

1
2
3
4
5
6
7
8
9
// 可注入的Mono基类,所有子类如果复写Awake, 需要base.Awake();

public class MonoInjected : MonoBehaviour
{
protected virtual void Awake()
{
EasyInjector.ReflectionInject(this);
}
}

只允许继承它才可以使用注入标签方式。

比如你A类需要调用B类一些成员,那么代码如下:

1
2
3
4
5
6
7
8
9
10
11
public class A : MonoInjected
{
[Inject]
public B m_b { get; set; }

public void Start()
{
m_b.成员或者函数; // 前提是B类成员和函数得public公开,否则无法调用
}

}

注入工具代码

EasyInjector.cs

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

/// <summary>
/// IoC容器
/// </summary>
public class EasyInjector
{
/// <summary>
/// 注入的类型和实例
/// </summary>
protected Dictionary<Type, object> m_dicInjection;

protected Dictionary<Type, List<InjectVO>> m_dlInjected;
protected Dictionary<Type, List<InjectVO>> m_dlUnjected;

// 单例
protected static EasyInjector _instance = null;

public static EasyInjector Instance
{
get
{
if (_instance == null)
{
_instance = new EasyInjector();
// 初始化词典
_instance.m_dicInjection = new Dictionary<Type, object>();
_instance.m_dlInjected = new Dictionary<Type, List<InjectVO>>();
_instance.m_dlUnjected = new Dictionary<Type, List<InjectVO>>();
}
return _instance;
}
}

public void AddInject<T>(T obj)
{
Type tt = typeof(T);

if (m_dicInjection.ContainsKey(tt))
m_dicInjection[tt] = obj;
else
m_dicInjection.Add(tt, obj);


if (m_dlUnjected.ContainsKey(tt))
{
if (!m_dlInjected.ContainsKey(tt))
m_dlInjected.Add(tt, new List<InjectVO>());

foreach (InjectVO ij in m_dlUnjected[tt])
{
ij.injectPpt.SetValue(ij.injectObj, obj, null);
m_dlInjected[tt].Add(ij);
}

m_dlUnjected.Remove(tt);
}
}

public void AddInject(Type type, object obj)
{
if (m_dicInjection.ContainsKey(type))
m_dicInjection[type] = obj;
else
m_dicInjection.Add(type, obj);


if (m_dlUnjected.ContainsKey(type))
{
if (!m_dlInjected.ContainsKey(type))
m_dlInjected.Add(type, new List<InjectVO>());

foreach (InjectVO ij in m_dlUnjected[type])
{
ij.injectPpt.SetValue(ij.injectObj, obj, null);
m_dlInjected[type].Add(ij);
}

m_dlUnjected.Remove(type);
}
}

public void RemoveInject<T>()
{
Type tt = typeof(T);
if (m_dicInjection.ContainsKey(tt))
m_dicInjection.Remove(tt);

if (m_dlInjected.ContainsKey(tt))
{
if (!m_dlUnjected.ContainsKey(tt))
m_dlUnjected.Add(tt, new List<InjectVO>());

foreach (InjectVO ij in m_dlInjected[tt])
{
ij.injectPpt.SetValue(ij.injectObj, null, null);
m_dlUnjected[tt].Add(ij);
}

m_dlInjected.Remove(tt);
}
}

public T GetInject<T>()
{
Type tt = typeof(T);
if (m_dicInjection.ContainsKey(tt))
return (T)m_dicInjection[tt];

return default(T);
}

public object GetInject(Type t)
{
if (m_dicInjection.ContainsKey(t))
return m_dicInjection[t];

return null;
}

protected void Injection(object injectTarget)
{
Type tp = injectTarget.GetType();

MemberInfo[] members = tp.FindMembers(MemberTypes.Property,
BindingFlags.FlattenHierarchy |
BindingFlags.SetProperty |
BindingFlags.Public |
BindingFlags.Instance,
null, null);
foreach (MemberInfo member in members)
{
object[] injections = member.GetCustomAttributes(typeof(Inject), true);

if (injections.Length > 0)
{
//Inject attr = injections[0] as Inject;
PropertyInfo ppt = member as PropertyInfo;
Type pptType = ppt.PropertyType;

var obj = EasyInjector.Instance.GetInject(pptType);
if (obj == null) // 尚未注入的对象
{
if (!m_dlUnjected.ContainsKey(pptType))
m_dlUnjected.Add(pptType, new List<InjectVO>());

m_dlUnjected[pptType].Add(new InjectVO(injectTarget, ppt));
}
else // 已注入的对象
{
if (!m_dlInjected.ContainsKey(pptType))
m_dlInjected.Add(pptType, new List<InjectVO>());

m_dlInjected[pptType].Add(new InjectVO(injectTarget, ppt));

ppt.SetValue(injectTarget, obj, null);
}
}
}
}

/// <summary>
/// 给外界提供的注入函数
/// </summary>
/// <param name="c">一个对象实例</param>
public static void ReflectionInject(object c)
{
EasyInjector.Instance.Injection(c);
}


/// <summary>
/// 数据实体类,一个类可以有多个[inject]属性
/// </summary>
public class InjectVO
{
public object injectObj;
// 一个类的属性信息
public PropertyInfo injectPpt;

public InjectVO(object target, PropertyInfo pptInfo)
{
injectObj = target;
injectPpt = pptInfo;
}
}
}


/*
// 在非Mono中使用注入,需要在类构造函数中调用EasyInjector.ReflectionInject(this);
// 自定义特性
// ValidOn
// 此位置参数指定指示的属性可放置到的程序元素。 AttributeTargets枚举中列出了可以放置属性的所有可能元素的集合。 可以使用按位AttributeTargets "或" 运算组合几个值, 以获取所需的有效程序元素组合。
// AllowMultiple
// 此命名参数指定是否可为给定的程序元素多次指定指定的属性。
// Inherited
// 此命名参数指定所指示的属性是否可由派生类和重写成员继承。
*/
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class Inject : Attribute // 自定义特性类必须直接或间接从Attribute继承
{
public object theObject { get; set; }

public Inject() { }

public Inject(object aobj)
{
theObject = aobj;
}
}
0%