And*_*tan 6 .net compiler-construction reflection
我正在研究如何ParameterInfo.IsOptional定义(我正在向内部IOC框架添加默认参数支持),在我看来,如果为true,则无法保证ParameterInfo.DefaultValue(或实际上ParameterInfo.RawDefaultValue)实际上是默认值适用.
如果你看一下给出IsOptional的MSDN示例,在IL中似乎可以定义一个可选的参数但是没有提供默认值(假设ParameterAttributes.HasDefault必须显式提供).即可能导致一种情况,一个参数的类型是,比如说Int32,ParameterInfo.IsOptional是真实的,但ParameterInfo.DefaultValue为空.
我的语言是C#,因此我可以什么工作,那编译器就行了.基于此我可以进行如下简单测试(parameter这是一个ParameterInfo实例,该方法旨在返回一个实例,用作参数的运行时参数):
if(no_config_value)
{
if(!parameter.IsOptional) throw new InvalidOperationException();
//it's optional, so read the Default
return parameter.DefaultValue;
}
else
return current_method_for_getting_value();
Run Code Online (Sandbox Code Playgroud)
但我认为某些语言(我希望在IL级别上做到这一点,而不仅仅是基于一个特定的编译器所做的)可以将责任放在调用者上以确定要使用的默认值,如果所以,default(parameter.ParameterType)需要按顺序进行.
这是一个有趣的地方,因为DefaultValue显然DBNull.Value(根据文档RawValue),如果没有默认值.如果参数是类型object和,这是不好的IsOptional==true!
已经做了较为挖掘一下,我希望,可靠的方式来解决,这是物理读取ParameterInfo.Attributes成员,读bitflags单独第一,检查ParameterAttributes.Optional和再检查ParameterAttributes.Default.只有两者都存在,那么阅读才是ParameterInfo.DefaultValue正确的.
我将开始编写代码并编写测试,但我希望有更多IL知识的人可以证实我的怀疑,并希望确认这对任何基于IL的语言都是正确的(因此避免模拟不同语言的库的负载!).
对我的问题的简短回答是否定的 - 只是因为这IsOptional是真的并不意味着DefaultValue实际上会包含真正的默认值.我在问题文本中更进一步的假设是正确的(.Net文档确实有点解释这个问题,以一种全面的方式).实质上,如果存在默认值,则调用者应该使用它,否则调用者应该提供它自己的默认值.参数Attributes用于确定是否存在默认值.
这就是我所做的.
假设存在以下方法:
/* wrapper around a generic FastDefault<T>() that returns default(T) */
public object FastDefault(Type t) { /*elided*/ }
Run Code Online (Sandbox Code Playgroud)
然后给出一个特定的参数和提供的参数值的Dictionary(来自配置):
public object GetParameterValue(ParameterInfo p, IDictionary<string, object> args)
{
/* null checks on p and args elided - args can be empty though */
object argValue = null;
if(args.TryGetValue(p.Name, out argValue))
return argValue;
else if(p.IsOptional)
{
//now check to see if a default is supplied in the IL with the method
if((p.Attributes & ParameterAttributes.HasDefault) ==
ParameterAttributes.HasDefault)
return p.DefaultValue; //use the supplied default
else
return FastDefault(p.ParameterType); //use the FastDefault method
}
else //parameter requires an argument - throw an exception
throw new InvalidOperationException("Parameter requires an argument");
}
Run Code Online (Sandbox Code Playgroud)
然后我在构造函数和方法上测试了这个逻辑:
public class Test
{
public readonly string Message;
public Test(string message = "hello") { Message = message; }
}
Run Code Online (Sandbox Code Playgroud)
IE,除了参数是可选的之外还提供默认值(程序正确地落入到达的分支中ParameterInfo.DefaultValue).
然后,在回答我问题的另一部分时,我意识到在C#4中我们可以使用它OptionalAttribute来生成一个没有默认值的可选参数:
public class Test2
{
public readonly string Message;
public Test2([OptionalAttribute]string message) { Message = message; }
}
Run Code Online (Sandbox Code Playgroud)
同样,程序正确地落入执行该FastDefault方法的分支中.
(在这种情况下,C#也将使用类型的默认值作为此参数的参数)
我认为这涵盖了所有 - 它在我尝试过的所有事情上都很好用(我很乐意尝试让重载决策感觉正确,因为我的IOC系统总是使用相当于命名的参数 - 但C#4规范帮助了那里).
| 归档时间: |
|
| 查看次数: |
1946 次 |
| 最近记录: |