前言
情景是这样,在快速做原型的时候不会去注意代码规范,只想快点写,导致一些想法废弃了,需要删除大量代码。大多数是获取物体为空导致。
对GetComponent判空的话就不会导致报错,有一堆不能用的代码也能正常跑测试。
实现方法
想到的办法有两个。
- 代码注入:这个办法在后续的使用应该是影响最小,应该。不过这是一个比较麻烦的方法,需要用工具,然后读一遍源码,也不是不行,后面有时间学注入了我会试一下可行性。
- 再包装一个GetComponent。这个使用起来还行,会不太习惯,但用也能用,我试的就是这个方法。不过变量需要在GetComponent的时候一起赋值,而且使用的是反射,所以性能有问题,但是原型嘛,没所谓的。
反射
c#的反射就不在这里介绍,去搜一下其他博客就行,这边只讲实现方法。
实现的话反射获取member是需要看类型的,字段,属性,事件,函数都提供不一样的获取函数和赋值操作,所以需要重载几个函数对应不同的类型。这里只写常用的字段,属性和函数。
还需要了解的就是Type类和Component类,这个比较简单,追一下Unity的代码,都是能直接看的。
那么首先获取Component,因为用自己方法包装了,所以还是多写点log,不然有意象之外的空值会不好找:
private static T GetComponent<T>(Transform tfm_root, string c) where T : Component
{
if (tfm_root == null)
{
Debug.LogWarning($"根节点为空,请检查");
return null;
}
var tfm_component = tfm_root.Find(c);
if (tfm_component == null)
{
Debug.LogWarning($"未获取到{tfm_component}对象,请检查");
return null;
}
var component = tfm_root.Find(c).GetComponent(typeof(T));
if (component == null)
{
Debug.LogWarning($"未获取到{component.name}对象,请检查");
return null;
}
return (T) component;
}
然后写两个赋值的函数就行:
public static void SetComponent<T>(Transform tfm_root, string c, string valueName = "", object value = null)
where T : Component
{
var component = GetComponent<T>(tfm_root, c);
if (component == null)
return;
FieldInfo field = typeof(T).GetField(valueName);
if (field != null)
field.SetValue(component, value);
PropertyInfo property = typeof(T).GetProperty(valueName);
if (property != null)
property.SetValue(component, value);
}
public static void SetComponent<T>(Transform tfm_root, string c, string valueName = "", object[] value = null)
where T : Component
{
var component = GetComponent<T>(tfm_root, c);
if (component == null)
return;
MethodInfo methodInfo = typeof(T).GetMethod(valueName);
methodInfo.Invoke(component, value);
}
使用
实际使用的话就像下面代码那样就行,这样后续物体删除后就不会报错,照常迭代就行:
public Transform tfm_test;
void Start()
{
//transform.Find("Cube").GetComponent<BoxCollider>().size=Vector3.zero;
SetComponent<BoxCollider>(tfm_test, "Cube", "size", Vector3.zero);
//transform.Find("").GetComponent<GongJu>().Method(1, "hello", true, new List<int> {1, 2, 3});
SetComponent<GongJu>(tfm_test, "", "Method", new object[4]
{
1,
"hello",
true,
new List<int> {1, 2, 3}
});
}
总结
这个不是一个好方法,充其量能用,算是献丑给一种思路。使用场景也比较奇怪,感觉优秀的继承关系还有一些宏定义的使用才是避免反复删除大量代码的正确方法。而且用这个办法废弃代码会越来越多,影响可读性。
只是在特殊的需求下,有了这个实现的想法。比较做原型不在乎代码可读性和性能,最重要的还是快速迭代。所以如果不幸真的有人用上了,那这方法总归有比没有好。