现在的位置: 首页 > 综合 > 正文

用自定义KeyValueCollection类代替Dictionary/Hastable,改善简化后的Entity性能

2012年12月08日 ⁄ 综合 ⁄ 共 6653字 ⁄ 字号 评论关闭
在上一篇《来一点反射,再来一点Emit —— 极度简化Entity!》中,Teddy运用反射和Emit极度简化了Entity的定义方式。本文将在上文的基础上,用自定义KeyValueCollection类代替原来的Dictionary类承载Entity的数据,从而改善Entity的读写性能,并保持Dictionary的方便的使用接口。

为什么Dictionary的性能不好?

当然,这里说的性能不好主要指相对于Private Field-Public Property方式的性能而言。我们知道,.Net2.0中的Dictionary类,实际上是一个泛型的HashTable实现。因此,性能不佳的原因主要就是HashTable算法。FantasySoft在他的文章《解读Hashtable》中为我们回顾了HashTable算法的原理。纵观整个算法,主要有以下几个地方的性能损失:一个是hashcode的计算,即计算key的hashcode的代码;第二个是hashcode重复的问题,此时,需要进行一个附加的链表查询。并且,Dictionary或HashTable都是通用类型,他们的太多代码,在这里完全没有用到,而白白浪费了实例化他们的内存开销。

为什么不直接使用Private Field-Public Property方式生成Entity?

那么,既然Private Field-Public Property方式的性能绝对是最好的,为什么Teddy又要定义自定义的KeyValueCollection呢?直接的原因是,对于我的已有代码,尤其是emit生成代码来讲,将Dictionary类承载数据改成Private Field-Public Property方式,代码的改动幅度过大,为了避免运行时反射的性能损失,IEntity接口中的方法可能都将不再适合定义在基类Enitity<>中,而必须直接动态emit,也因此,虽然明知Private Field-Public Property的性能最好,但是,我并不愿意冒然向他缴械。也因此,如本文标题,Teddy开始尝试使用自定义的KeyValueCollection来代替Dictionary,希望能够获得和Private Field-Public Property相似的性能,但是又有Dictionary的那样的简单使用接口。

自定义KeyValueCollection!

考虑到我的KeyValueCollection只是用于持久化内部的数据承载,我不需要太大的通用性,只需要必要的接口就好,我将KeyValueCollection类定义如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Ilungasoft.Helper.Data
{
    
public class KeyValueCollection
    
{
        
private string[] keys;
        
private object[] values;

        
private KeyValueCollection()
        
{
        }


        
public KeyValueCollection(params PropertyInfo[] pis)
        
{
            
if (pis != null)
            
{
                keys 
= new string[pis.Length];
                values 
= new object[pis.Length];
                
for (int i = 0; i < pis.Length; i++)
                
{
                    keys[i] 
= pis[i].Name;
                    values[i] 
= typeof(Util).GetMethod("DefaultValue", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(pis[i].PropertyType).Invoke(nullnull);
                }

            }

            
else
            
{
                keys 
= new string[0];
                values 
= new object[0];
            }

        }


        
public string[] GetKeys(params string[] exceptKeys)
        
{
            
if (exceptKeys != null && exceptKeys.Length > 0)
            
{
                
int retKeyCount = keys.Length - exceptKeys.Length;
                
if (retKeyCount <= 0)
                
{
                    
return new string[0];
                }

                List
<string> retKeys = new List<string>(retKeyCount);
                
foreach (string key in keys)
                
{
                    
bool isExcept = false;
                    
foreach (string exceptMember in exceptKeys)
                    
{
                        
if (key.Equals(exceptMember))
                        
{
                            isExcept 
= true;
                            
break;
                        }

                    }

                    
if (!isExcept)
                    
{
                        retKeys.Add(key);
                    }

                }

                
return retKeys.ToArray();
            }

            
else
            
{
                
return keys;
            }

        }


        
public object[] GetValues(params string[] exceptKeys)
        
{
            
if (exceptKeys != null && exceptKeys.Length > 0)
            
{
                
int retValueCount = keys.Length - exceptKeys.Length;
                
if (retValueCount <= 0)
                
{
                    
return new object[0];
                }

                List
<object> retValues = new List<object>(retValueCount);
                
for (int i = 0; i < keys.Length; i++)
                
{
                    
bool isExcept = false;
                    
foreach (string exceptMember in exceptKeys)
                    
{
                        
if (keys[i].Equals(exceptMember))
                        
{
                            isExcept 
= true;
                            
break;
                        }

                    }

                    
if (!isExcept)
                    
{
                        retValues.Add(values[i]);
                    }

                }

                
return retValues.ToArray();
            }

            
else
            
{
                
return values;
            }

        }


        
public KeyValueCollection Clone()
        
{
            KeyValueCollection retKeyValues 
= new KeyValueCollection();
            
string [] cloneKeys = new string[keys.Length];
            keys.CopyTo(cloneKeys, 
0);
            retKeyValues.keys 
= cloneKeys;
            
object[] cloneValues = new object[values.Length];
            values.CopyTo(cloneValues, 
0);
            retKeyValues.values 
= cloneValues;
            
return retKeyValues;
        }


        
public object this[int index]
        
{
            
get
            
{
                
return values[index];
            }

            
set
            
{
                values[index] 
= value;
            }

        }

    }

}

接着,还要将原来对Dictionary的调用全都改成对新的类的调用,基类Entity<>的改动不太大,我就不列举了,运行时生成的Entity改动就比较大了。使用新的KeyValueCollection类后,实际生成的Entity的代码的范例列举如下(IAbout为需要用户定义的接口,static EntityFactory()为修改后的生成运行时About类的emit代码,最后的About为,实际上emit出来的类的等价hard code代码):

using System;

namespace Ilungasoft.Helper.TestApp.DomainObject2
{
    
public interface About: Ilungasoft.Helper.Data.IEntity
    
{
        
int ID getset; }

        
string Title getset; }

        
string Content getset; }

        
bool Deletable getset; }

        
int Order getset; }
    }

}

        static EntityFactory()
        
{
            
//create dynamic IEntity Assembly & Type through Emit
            if (assBuilder == null)
            
{
                AssemblyName assName 
= new AssemblyName();
                assName.Name 
= DYNAMIC_ENTITY_NAMESPACE;
                assBuilder 
= AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
            }


            
if (modBuilder == null)
            
{
                modBuilder 
= assBuilder.DefineDynamicModule(DYNAMIC_ENTITY_NAMESPACE);
            }


            
if (typeBuilder == null)
            
{
                typeBuilder 
= modBuilder.DefineType(DYNAMIC_ENTITY_NAMESPACE + "." + typeof(IEntityType).FullName, TypeAttributes.Public);
                typeBuilder.AddInterfaceImplementation(
typeof(IEntityType));
                Type keyValuesType 
= typeof(KeyValueCollection);
                Type baseType 
= typeof(Entity<IEntityType>);
                typeBuilder.SetParent(baseType);
                PropertyInfo[] pis 
= typeof(IEntityType).GetProperties();

                
//define SetPropertyValue(string key, object val)
                MethodInfo mi = typeof(IEntity).GetMethod("SetPropertyValue");
                ParameterInfo[] paramInfos 
= mi.GetParameters();
                
int paramlength = paramInfos.Length;
             

抱歉!评论已关闭.