Default Value Attribute Based Approach to Property Initializton
20255 ワード
参考資料1:http://www.barsoom.org/defaultvalue-attribute-initial
Initialization using PropertyDescriptore.ReetValue(…)
The next method is very simiar to the
The re is a showed property for this propertyThe re is a
Collappse
| Copyコード
Initialization with Delegates
The previous two algorithms are relatively slow.A lot of computter cycles are spent on iterating through collection and searching for corect methods to call.The ir performance could proved proved alive methods were rereved only once and if their references were stored in cache for later use.
Collappse
| Copyコード
This appech creates the most freexible and coplete mechans for reetting properties to their default values.Compred to other methmans,it also improves their performance by elimination necessarititationit still does not favorably compre to the direct initialization method.
Initialization with Prcompled Setters
The solution with caching of delegates eliminates repetive queries for the
By using lamda expressions、we can generate a custom code at run time、and create the following method:
List of these expressions could be compled and added to a multicast delegate for further use.
Collappse
| Copyコード
This aproach requires considersable reource and time during initiazation of its first instance、but eliminates all of the overhead assited with the use of
public class TestClass
{
[DefaultValue(1)]
public int IntProperty { get; set; }
[DefaultValue(1)]
public long LongProperty { get; set; }
[DefaultValue(true)]
public bool BoolProptrty { get; set; }
}
public Constructor()
{
// Iterate through each property
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
{
// Set default value if DefaultValueAttribute is present
DefaultValueAttribute attr = prop.Attributes[typeof(DefaultValueAttribute)]
as DefaultValueAttribute;
if (attr != null)
prop.SetValue(this, attr.Value);
}
...
}
コードのプレゼンテーション:class Program
{
static void Main(string[] args)
{
TestClass tc = new TestClass();
Console.WriteLine(tc.aa);
Console.WriteLine(tc.LongProperty);
Console.WriteLine(tc.BoolProptrty);
Console.ReadLine();
}
}
public class TestClass
{
[DefaultValue("jon")]
public string aa { get; set; }
[DefaultValue(1)]
public long LongProperty { get; set; }
[DefaultValue(true)]
public bool BoolProptrty { get; set; }
public TestClass()
{
//or=>
//foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(typeof(TestClass)))
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
{
// Set default value if DefaultValueAttribute is present
DefaultValueAttribute attr = prop.Attributes[typeof(DefaultValueAttribute)]
as DefaultValueAttribute;
if (attr != null)
prop.SetValue(this, attr.Value);
}
}
}
出力効果:jon
1
true
参考資料1改订版:http://www.codeproject.com/Articles/66073/DefaultValue-Attribute-Based-Approach-to-Property Initialization using PropertyDescriptore.ReetValue(…)
The next method is very simiar to the
ComponentModel
Initialization aproach except it uses method ofPropertyDescriptor
クラスcaled ReetValue(…).Acctording to MSDN documentation、this method reets property to the value determined in the follwing order of precedence:The re is a showed property for this propertyThe re is a
DefaultValueAttribute
for this propertyThe re is a「ResetMyProperty
」method has been implemented、where「MyProperty
」is the property being reet.So the code for this implemention looks like this:Collappse
| Copyコード
public Constructor()
{
// Iterate through each property and call ResetValue()
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
property.ResetValue(this);
...
}
This aproach creates a more flexible solution as opposed to the direct querying of DefaultValue
atributes.It provides alternative ways of reetting a property s value but does not improve its performance.Initialization with Delegates
The previous two algorithms are relatively slow.A lot of computter cycles are spent on iterating through collection and searching for corect methods to call.The ir performance could proved proved alive methods were rereved only once and if their references were stored in cache for later use.
Collappse
| Copyコード
private static Action<object><this> setter; // Reset multicast delegate
public Constructor()
{
// Attempt to get it from cache
if (null == setter)
{
// If no initializers are added do nothing
setter = (o) => { };
// Go through each property and add method calls to multicast delegate
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
{
// Add only these which values can be reset
if (prop.CanResetValue(this))
setter += prop.ResetValue;
}
}
// Initialize member properties
setter(this);
}
This algorithm is simiar to the previous two、but instead of caling ResetValue
method on each property,it adds the method’s reference to the multiast delegate.Onece all of the properties arit,invoking this delettes the m to the mut the propris values.Each consecutive instantiation ofThis appech creates the most freexible and coplete mechans for reetting properties to their default values.Compred to other methmans,it also improves their performance by elimination necessarititationit still does not favorably compre to the direct initialization method.
Initialization with Prcompled Setters
The solution with caching of delegates eliminates repetive queries for the
ResetValue
methods.Unfortunally,it still searches for the default value for each property on evercal.If neither a showed property,nor the vatrate“ResetValue
”methods ares to initiaze default values,thesearemberge properchect ResetMyProperty
atribute only once and stored alone with the approprate DefaultValue
delegate in cache for further use.By using lamda expressions、we can generate a custom code at run time、and create the following method:
SetValue
where (object o){ o.PropertySetter(constant); }
is an instance of the object, o
is a delegate to an approprate set method、andPropertySetter
is a value retrieved from constant
atribute.List of these expressions could be compled and added to a multicast delegate for further use.
Collappse
| Copyコード
// Default Value multicast delegate
private static Action<object><this> setter;
public CompiledComponentModelInitialization()
{
// Attempt to get it from cache
if (null == setter)
{
ParameterExpression objectTypeParam = Expression.Parameter(typeof(object),
"this");
// If no initializers are added do nothing
setter = (o) => { };
// Iterate through each property
foreach (PropertyInfo prop in this.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance))
{
// Skip read only properties
if (!prop.CanWrite)
continue;
// There are no more then one attribute of this type
DefaultValueAttribute[] attr = prop.GetCustomAttributes(
typeof(DefaultValueAttribute), false) as DefaultValueAttribute[];
// Skip properties with no DefaultValueAttribute
if ((null == attr) || (null == attr[0]))
continue;
// Build the Lambda expression
// Create constant expression with value from DefaultValue attribute
// and convert it into appropriate type
Expression dva = Expression.Convert(Expression.Constant(attr[0].Value),
prop.PropertyType);
// Create expression describing call to appropriate setter and
// passing it instance and value parameters
Expression setExpression = Expression.Call(Expression.TypeAs(
objectTypeParam, this.GetType()),
prop.GetSetMethod(), dva);
// Create lambda expression describing proxy method which receives
// instance parameter and calls instance.setter( constant )
Expression<Action<object><action><this>> setLambda =
Expression.Lambda<action><this><Action<object><action><this>>(
setExpression, objectTypeParam);
// Compile and add this action to multicast delegate
setter += setLambda.Compile();
}
}
// Initialize member properties
setter(this);
}
The first time this class'instance is created、all of the DefaultValue
writeable properties art iterated through、Lamda Expressions are created、compled and added to a multiast delegate.Next time abject of this type is instantiated、these precompiled methods aritits are.This aproach requires considersable reource and time during initiazation of its first instance、but eliminates all of the overhead assited with the use of
public
atributes during all other instance initializations.In terms of performance,this the only algorithm that compres very well to the direct initialization methode proxy methods and compled.using System;
using System.Linq;
using AOP;
namespace YourNamespace
{
public class YourClass
{
public Constructor()
{
this.ApplyDefaultValues();
}
...
}
}