工作在。net 4.5.
我正在制作封装ActiveX控件(具体来说是CadCorp SIS ActiveX控件)的类,并且基本上复制了该控件内部可用的一些对象(但不是外部)。从外部来看,内部对象的属性必须使用接受文本字符串的API来操作。
在每个类中,我最终通过API编写获取和设置值的属性,并且它基本上是一遍又一遍地重复相同的代码,例如Control.GetInt(TargetDescripor, TargetIdentifier, PropertyName);
,所以我试图使用泛型将代码减少到最小。我现在有了这样一个方法:
public T GetPropertyValue<T>(ObjectTypes Target, string PropertyName, int TargetIdentifier = 0)
,它标识正确的API方法并返回所需的值。
我仍然需要从每个具有正确描述符和正确属性名的对象调用此方法。我已经进一步减少了。例如,如果我在一个对象中获得属性,我使用以下代码:
public Class MyObject
{
public bool MyObjectPropertyX
{
get { return this.GetProperty<bool>(); }
}
private const string _MyObjectPropertyX = "APICommandString";
private T GetPropertyValue<T>([CallerMemberName] string PropertyName = null)
{
string apiCommand = (string)this.GetType().GetField("_" + PropertyName, BindingFlags.NonPublic | BindingFlags.Static).GetValue(this);
// Call the method which executes the API command with the correct object
// descriptor and get the value
}
}
这个效果很好
现在我想知道是否有可能在属性的getter中调用this.GetProperty<T>()
,类型参数被自动设置为属性的类型?这可行吗?还是说我现在拥有的已经够好了?
另外,我很想知道采用这种方法是否有任何缺点。我将不得不做很多API调用,所以我想知道如果使用反射实际上会减慢这与原始代码相比,我在每个getter和setter显式调用适当的方法?
解决你的第一点,我不认为你会进一步减少get
代码没有过度复杂化;对我来说,只要指定类型就行了。
如果您希望能够在不硬编码字符串的情况下确定属性名称,您可以将此方法与反射一起使用。
关于性能,我要说的首先是:测试它。如果您发现它很慢,那么您可以尝试缓存查找属性操作。这段代码将把反射的field.getValue
调用包装在一个Func<string>
中,这样就不需要每次都进行反射查找。请记住,反射api在内部做了一些缓存,所以这样做可能没有什么好处。
private readonly IDictionary<String, Func<String>> _cache = new Dictionary<String, Func<String>>();
private String GetApiCommand(String propertyName)
{
Func<String> command;
if (_cache.TryGetValue(propertyName, out command))
{
return command();
}
var field = GetType().GetField("_" + propertyName, BindingFlags.NonPublic | BindingFlags.Static);//.GetValue(this);
if (field != null)
{
Func<String> action = () => (String)field.GetValue(this);
_cache[propertyName] = action;
return action();
}
throw new NotSupportedException();
}