写这次这一篇的原因是来自一个CSDN网友找到我提出了一个拷问:
知名网友:“我想把下面的代码放到
C# Script
电池里,怎么加?”public override TimeSpan ProcessorTime { get { if (setUp) return TimeSpan.Zero; else return base.ProcessorTime; } }
知名网友:“我的目的是想让这个脚本电池不显示运行时间,不知道怎么处理了。”
我品了品,emmm,想要让C# Script
电池不显示运行时间,大致是把这个去掉的意思吧:
在自己编译电池里写这个还蛮简单的,就是网友给出的这段代码直接一个override
就完事儿了,本质上是在Grasshopper询问ProcessorTime
属性(也就是用来展示在电池下方的“处理用时”)时,在某种条件下直接返回TimeSpan.Zero
来“谎称”自己零耗时。
但是要在C# Script
电池里做这个事儿嘛… 本质上是需要在C# Script
电池内通过Component
这个属性值拿到电池本身,然后再设置这个ProcessorTime
属性。但是,由于C# Script
电池不是我们自己写的,我们似乎拿到了也没用,这玩意儿就是一个get
属性,我们没法往里设置值啊,啊这……
不过,我们还是可以通过反编译来看看这个ProcessorTime
是怎么个get
到值的嘛,我们把它背后的值设置一下不就完了?打开Visual Studio
,对着GH_Component
直接进行一个F12
的戳,戳就完事儿了。
戳完直接Ctrl
+F
搜索关键词ProcessorTime
,定睛一看:
好家伙,是要去找_profiledSpan
这个变量。再次Ctrl
+F
,喵喵喵?private
?
众所周知,private
的变量没法直接在类的外部获取/赋值,这可咋整?
此时,那就必须得祭出反射了。
反射可以在程序运行时获取所有对象的任何属性或字段,并更改。Peroid。
直接:
typeof(GH_Component).GetField("_profiledSpan",
BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(Component, TimeSpan.Zero);
把这段代码放到: (顶部有using System.Reflection;
以及using System.Threading;
)
诶嘿,虽然上面有个Thread.Sleep(500)
的大老虎,但是这电池压根不显示运行时长。作为对比,再放个电池在它旁边,没有这段神秘代码的:
至此就完成了这个简单的功能… (Grasshopper作者:“我做这功能是给你这么用的?”)
好了,上面的只是前菜。正餐先挖个坑,这里简单讲讲上面那段运用反射的逻辑:
typeof(GH_Component)
用来获得“想要设置的属性/字段定义在哪个类里”GetField(string name, BindingFlags flags)
用来获得“这个类的具体的字段”SetValue(object obj, object value)
用来将具体的某个值设置到obj
这个对象的刚刚获取到的“这个类的这个具体的字段”里去
上面的BindingFlags
里用到了“位运算符” |
。详情请见:位运算符和移位运算符(C# 参考)
这里输入了BindingFlags.Instance | BindingFlags.NonPublic
是为了能够获取到标记为private
的属性。
从BindingFlags.NonPublic
的名字我们也可以看出来,它是用来获取非public
的内容,比如private
或者protected
。
BindingFlags.Instance
则是声明获取“成员”内容,而非“静态”内容,也就是没有被static
标记的内容。
Cool,这期前菜就先到这,反射在Grasshopper里的应用下次再见。🦀