. NET Get enumeration DescriptionAttribute Description of information Performance improvement methods _ practical skills

Source: Internet
Author: User
Tags reflection

I. GENERAL use of DescriptionAttribute

1.1 Using the example

The DescriptionAttribute feature can be used in many places, and the more common is enumeration, which is displayed on the UI by getting the descriptive information defined on the enumeration, a simple enumeration definition:

Public enum Enumgender
{
None,
[System.ComponentModel.Description ("Man")]
Male,
[ System.ComponentModel.Description ("female")]
Female, other
,

This article does not discuss the other application scenarios of DescriptionAttribute, and does not pay attention to the implementation of multi-language, only the method of obtaining enumeration description information is simply studied.

The most common way to get enumeration descriptive information is to search for similar code in the garden as much as possible.

The public static string Getdescriptionoriginal (the This Enum @this)
{
var name = @this. ToString ();
var field = @this. GetType (). GetField (name);
if (field = null) return name;
var att = System.Attribute.GetCustomAttribute (field, typeof (DescriptionAttribute), false);
return ATT = null? Field. Name: ((DescriptionAttribute) att). Description;
}

The simple test:

Console.WriteLine (EnumGender.Female.GetDescriptionOriginal ());
Console.WriteLine (EnumGender.Male.GetDescriptionOriginal ());
Console.WriteLine (EnumGender.Other.GetDescriptionOriginal ()); Output result: 
female 
male and other 

1.2 The implementation code above the problem

The first thing to understand is what is the feature?

Characteristics:

Attribute attributes are metadata that is associated with a section of the target object's configuration information, stored in the DLL. It has no meaning in itself and can be used to get the configuration information through reflection.

So the main problem is actually the severity of the reflection:

·1. Each call will use reflection, slow efficiency!
2. Each invocation of reflection generates a new DescriptionAttribute object, even the same enumeration value. resulting in a great waste of memory, GC!
3. It doesn't seem to support a bit-field combination Object!
4. The method parameter of this place is Enum,enum is the base class of the enumeration, he is a reference type, and the enumeration is a value type, this method can cause boxing, but the problem seems unavoidable.

How bad is the performance? Code to measure:

[Test]
public void Getdescriptionoriginal_test ()
{
var enums = this. Gettestenums ();
Console.WriteLine (enums. Count);
Testhelper.invokeandwriteall (() =>
{
System.Threading.Tasks.Parallel.For (0, 1000000, (i, obj) =>
{
foreach (var item in enums)
{
var a = Item. Getdescriptionoriginal ();
}
}
);} Output results:
timespan:79,881.0000ms//Total consumption of nearly 80 seconds
memoryused:-1,652.7970kb

which this. The Gettestenums () method uses a collection of enumerated values for testing, the collection size 80, executed 100w, equivalent to the 8000w getdescriptionoriginal method.

Testhelper.invokeandwriteall method is used to calculate the time before and after the memory consumption, 0-generation GC recovery times, the end of the article in the appendix to the code, due to the memory recovery reasons, memory consumption calculation is actually inaccurate, However, you can refer to the third indicator 0 generation GC collection times.

Two. Improved DescriptionAttribute method

Know the cause of the problem, the solution is good to do, the basic idea is to get the text value of the cache, an enumeration value only reflection once, so the performance problem is solved.

2.1 Using dictionary caching + Locks

Because using a static variable dictionary to cache values, it involves thread safety, which requires the use of locks (double detection), specific methods:

private static Dictionary<enum, string> _lockdictionary = new Dictionary<enum, string> ();
public static string Getdescriptionbydictionarywithlocak (this Enum @this)
{
if _lockdictionary.containskey ( @this)) return _lockdictionary[@this];
Monitor.Enter (_obj);
if (!_lockdictionary.containskey (@this))
{
var value = @this. Getdescriptionoriginal ();
_lockdictionary.add (@this, value);
}
Monitor.Exit (_obj);
return _lockdictionary[@this];

To test, the test data, the number of times and 1.2 of the same getdescriptionoriginal_test, efficiency has been greatly improved, only one time memory recovery.

[Test]
public void Getdescriptionbydictionarywithlocak_test ()
{
var enums = this. Gettestenums ();
Console.WriteLine (enums. Count)
Testhelper.invokeandwriteall (() =>
{
System.Threading.Tasks.Parallel.For () (0, 1000000, (i), obj =>
{
foreach (var item in enums)
{
var a = Item. Getdescriptionbydictionarywithlocak ();
}
}
);} Test results:
timespan:1,860.0000ms
memoryused:159.2422kb

2.2 Using Dictionary caching + exceptions (way out of the ordinary way)

Let's take a look at the implementation method first.

private static Dictionary<enum, string> _exceptiondictionary = new Dictionary<enum, string> ();
public static string Getdescriptionbydictionarywithexception (this Enum @this)
{
try
{return
_ exceptiondictionary[@this];
}
catch (KeyNotFoundException)
{
monitor.enter (_obj);
if (!_exceptiondictionary.containskey (@this))
{
var value = @this. Getdescriptionoriginal ();
_exceptiondictionary.add (@this, value);
}
Monitor.Exit (_obj);
return _exceptiondictionary[@this];
}

Let's say our scenario is this: there are not many enumerations in the definition of the project, but they are often described in a way that defines a user's sex enumeration, uses a lot of places, and uses a high frequency.

In the Getdescriptionbydictionarywithlocak method above, the first code "if" (_lockdictionary.containskey (@this)) is to verify that the enumeration value is included. 8000w was executed in the 2.1 test, of which only 80 (a total of 80 enumerated values were used for testing) required This Code "if (_lockdictionary.containskey (@this))" and the rest of the direct value is available. Based on this consideration, there is the above method of Getdescriptionbydictionarywithexception.

Let's test it and see how it works!

[Test]
public void Getdescriptionbydictionarywithexception_test ()
{
var enums = this. Gettestenums ();
Console.WriteLine (enums. Count);
Testhelper.invokeandwriteall (() =>
{
System.Threading.Tasks.Parallel.For (0, 1000000, (i, obj) =>
{
foreach (var item in enums)
{
var a = Item. Getdescriptionbydictionarywithexception ();
}
}
);} Test results:
timespan:1,208.0000ms
memoryused:230.9453kb
collectioncount (0): 1.00

Test results, basically almost, a little bit happier in time, 1,208.0000ms:1,860.0000ms, perform 8000w times fast 600 milliseconds, as if the difference is not ah, this is why?

This is actually the problem of dictionary, dictionary internal use hashing algorithm to compute the storage address, its search time complexity of O (1), his search effect is very fast, and this method uses the exception processing, the exception capture itself has a certain performance impact.

2.3 Recommended simple scheme: concurrentdictionary

Concurrentdictionary is a thread-safe dictionary class, code:

private static Concurrentdictionary<enum, string> _concurrentdictionary = new Concurrentdictionary<enum, String> ();
public static string Getdescriptionbyconcurrentdictionary (this Enum @this)
{return
_ Concurrentdictionary.getoradd (@this, (key) =>
{
var type = key. GetType ();
var field = type. GetField (key. ToString ());
return field = null? Key. ToString (): getdescription (field);
});

Test code and test results:

[Test]
public void Getdescriptionbyconcurrentdictionary_test ()
{
var enums = this. Gettestenums ();
Console.WriteLine (enums. Count);
Testhelper.invokeandwriteall (() =>
{
System.Threading.Tasks.Parallel.For (0, 1000000, (i, obj) =>
{
foreach (var item in enums)
{
var a = Item. Getdescriptionbyconcurrentdictionary ();
}
}
);} Test results:
timespan:1,303.0000ms
memoryused:198.0859kb

2.4 Official Code

To sum up, the formal code that addresses performance issues, bit-domain enumeration issues:

<summary>///Gets the descriptive information for the enumeration (descripion).
A bit field is supported, if it is a bit-field combination value, multiple delimiters are grouped. </summary> public static string GetDescription (this Enum @this) {return _concurrentdictionary.getoradd (@this, (key) => {var type = key.
GetType (); var field = type. GetField (key.
ToString ()); If field is null, it should be a combination bit field value, return field = null? Key.
Getdescriptions (): getdescription (field);
}); ///<summary>///Gets a description of the bit-field enumeration, multiple by-separator combination///</summary> public static string Getdescriptions (this Enum @this, St Ring separator = ",") {var names = @this. ToString ().
Split (', '); string[] res = new String[names.
Length]; var type = @this.
GetType (); for (int i = 0; i < names. Length; i++) {var field = type. GetField (Names[i].
Trim ());
if (field = null) continue;
Res[i] = getdescription (field); return string.
Join (separator, res); private static string GetDescription (FieldInfo field) {var att = System.Attribute.GetCustomAttribute (field, typeof (Des
Criptionattribute), false); return ATT = null? Field. NaMe: ((DescriptionAttribute) att).
Description;

 }

Ps:. NET gets the description of the enumeration value

How to define a description for an enumeration value

Public enum TimeOfDay 
{ 
[Description ("Morning")] 
moning = 1, 
[Description ("Afternoon")] 
afternoon = 2, 
[ Description ("Evening")] 
Evening = 3, 

Methods to get a description of the enumeration value

public static string Getdescriptionfromenumvalue (Type enumtype, Object enumvalue)
{
Try
{
Object o = Enum.parse (Enumtype, enumvalue.tostring ());
String name = O.tostring ();
Descriptionattribute[] CustomAttributes = (descriptionattribute[]) Enumtype.getfield (name). GetCustomAttributes (typeof (DescriptionAttribute), false);
if (customattributes!= null) && (customattributes.length = 1))
{return
customattributes[0]. Description;
}
return name;
Catch
{return
"Unknown";
}
}

Iii. use of methods to get descriptions of enumeration values

 string strmoning = Getdescriptionfromenumvalue (typeof (TimeOfDay), 2); 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.