真是不够聪明:老外写的程序看得头疼?帮位大哥指点一下!

解决方案 »

  1.   


    真是不够聪明:老外写的程序看得头疼?帮位大哥指点一下!我的理解:把反射的类结构信息存入静态哈希表中?  但不理解他为什么要这么做?
    目的是什么?是深度拷贝还浅拷贝?1、一个拷贝抽象类:    [Serializable]
        public abstract class CSCopy
        {
            private static readonly Hashtable objects = new Hashtable();        protected object CreateNewInstance()
            {
                ConstructorInfo ci = objects[this.GetType()] as ConstructorInfo;
                if(ci == null)
                {
                    ci = this.GetType().GetConstructor(new Type[0]);
                    objects[this.GetType()] = ci;
                }            return ci.Invoke(null);
            }        public virtual object Copy()
            {
                return CreateNewInstance();   
            }
        }
    2、实际应用:public class IndexPost : CSCopy
    {
            /// <summary>
            /// 重写拷贝
            /// </summary>
            /// <returns></returns>
            public override object Copy()
            {
                IndexPost post = base.Copy () as IndexPost;     post.BestMatch = this.BestMatch;
                post.Body = this.Body;
                post.Title = this.Title;
            }
       。。
    }
    IndexPost post = base.Copy () as IndexPost;不明白他为什么要这样做呢?是深度拷贝还浅拷贝?按我的理解:如果深度拷贝应该用:IndexPost post = new IndexPost();这不是更加简洁吗?老外为什么要又反射又拷贝,啥意思啊?睬不透老外的奥妙之处?特向各位大哥求教了。
      

  2.   

    但他每次都是在: ci.Invoke(null); 好像看不到缓存有多大的效果啊....
      

  3.   

    IndexPost post = new IndexPost();
    这怎么能算copy呢???这根本是个空对象嘛                ci = this.GetType().GetConstructor(new Type[0]); 
                    objects[this.GetType()] = ci; 
    就是要把带参的构造信息ci存入hashtable这个ci.Invoke(null); 就能反回对象了
      

  4.   

    IndexPost post = new IndexPost(); 
    这怎么能算copy呢???这根本是个空对象嘛 
    我说的这个是在Copy方法呢? 可以实现深度拷贝.....
      

  5.   

    即使是从缓存中取出, 但是每次都要这样: 
    return ci.Invoke(null); 似呼也是相当消耗资源啊??? 他为什么要这么做, 想不通啊.
      

  6.   

    写为class其实非常麻烦,因为有很多类型希望有自己的父类来源,所以一个方法设计不应该随便标榜为父类。根据它的大致意思,我这里写了一个扩展方法,与之对照:    public static class Extention
        {        public T CreateNewObject<T>(this T template) where T : new()
            {
                return new T();
            }        private static readonly Dictionary<Type, ConstructorInfo> ConstructorBuffer = new Dictionary<Type, ConstructorInfo>();        public object CreateNewObject(this object template)
            {
                ConstructorInfo ci;
                if (!ConstructorBuffer.TryGetValue(template.GetType(), out ci))
                {
                    Type tt=template.GetType();
                    ci = tt.GetConstructor(new Type[0]);
                    if(ci==null)
                        throw new Exception(string.Format("必须为类型【{0}】设置一个无参数的实例化方法。", tt.FullName);                ConstructorBuffer .Add( tt, ci);
                }
                return ci.Invoke(null);
            }
        }
      

  7.   

    嗯,上面少写了一个“)”括号,另外方法请补上声明为static的。使用时,只要引用了这个Extention所在的命名空间,对于任何对象,你就都可直接调用其CreateNewObject方法。例如已知TA类型的变量x中已经保存了某个对象,可以这样复制另一个:   TA y=x.CreateNewObject();
        
      

  8.   

    其实,我写        public T CreateNewObject<T>(this T template) where T : new()
            {
                return new T();
            }
    只是为了跟“来外”写的代码取得接口格式上的一致。你可以看到,这个参数template根本是多余的。后边一个方法也有点类似,实际上只要给一个Type类型的参数按说就完全可以,不知道为什么一定要传一个对象进来。不过学习和真实的软件开发是不同的,开发时没有必要那么死抠。大项目的开发是靠质量管理手段来保证整体上的质量和进度的,只要达到原先设计的功能就算通过,而不是对每一个程序员的每一个代码都向来是审查学生一样对“标准、效率”之类的东西过分审查。
      

  9.   

    根据这个手段的初衷,我可以再扩展一点:    public static class Extention
        {        public static T CreateNewObject<T>(this T obj) where T : new()
            {
                return new T();
            }        public static void CopyValuesTo<T>(this T source, T target)
            {
                foreach (FieldInfo fld in typeof(T).GetFields())
                    fld.SetValue(target, fld.GetValue(source));
                foreach (PropertyInfo pro in typeof(T).GetProperties())
                    pro.SetValue(target, pro.GetValue(source, null), null);
            }     }
    这样,假设我们要把保存了实例化了的TA类型的对象的变量x复制到变量y(仅复制一层属性值),可以调用:    TA y=x.CreateNewObject();
       x.CopyValuesTo(y);
      

  10.   

    OH OH,我在半分钟前已经把这个东西加入我的最通用的工程做作为工具了。确实可以用在很多地方的。我我在类库最终加入的代码是:     public static class Extention
        {        public static T CreateNew<T>(this T obj) where T : new()
            {
                return new T();
            }        public static void CopyValuesTo<T>(this T source, T target)
            {
                foreach (FieldInfo fld in typeof(T).GetFields())
                    fld.SetValue(target, fld.GetValue(source));
                foreach (PropertyInfo pro in typeof(T).GetProperties())
                    if (pro.CanRead && pro.CanWrite)
                        pro.SetValue(target, pro.GetValue(source, null), null);
            }.......
      

  11.   


    TO: sp1234    大哥的改进方法确实不错, 把父类独立出来做为一个通用的静态类供调用.....
    不错的方法...
      

  12.   

    TO: sp1234     我查了一下以前写的代码, 发现有一处和你的实现也类似, 就是通过遍历获取字段属性值, 但后来发现效率是个大问题. 测试时发现: 遍历100次消耗:1031毫秒,如果不调用外部的特性缩写名称,而是直接引用属性的名称,速度则提高到:796毫秒,但是这样的速度仍然不能让人接受。    因此简洁的代码, 有时往往是好看, 却不能实际应用.... 真是郁闷......        /// <summary>
            /// 处理属性
            /// </summary>
            /// <param name="baseObject"></param>
            /// <returns></returns>
            private static string ProcessProperties(object baseObject)
            {
                // 读取对象属性数组集合
                //PropertyInfo[] properties = baseObject.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
                PropertyInfo[] properties = baseObject.GetType().GetProperties();
                //ArrayList cachekeys = new ArrayList();
                // 注意:改用泛型类后比ArrayList要节省一半的时间
                System.Collections.Generic.List<string> cachekeys = new System.Collections.Generic.List<string>();            // 遍历属性数组
                foreach (PropertyInfo pi in properties)
                {
                    try
                    {
                        // 下面逻辑式非常消耗时间
                        //if (pi.CanRead && !IsIgnored(pi) && !IsIgnoredDefaultValue(pi, pi.GetValue(baseObject, null)))
                        //{
                            //cachekeys.Add(string.Format("{0}:{1}", KeyName(pi), pi.GetValue(baseObject, null)));
                            cachekeys.Add(string.Format("{0}:{1}", pi.Name, pi.GetValue(baseObject, null)));
                        //}
                    }
                    catch //(NullReferenceException nex)
                    {
                    }
                }            //// CS-2533: CacheKey.GetCacheKey() reflection needs a sort order
                //// This should use the current culture for comparison
                cachekeys.Sort();            //return string.Join("-", (string[])cachekeys.ToArray(typeString));
                return string.Join("-", (string[])cachekeys.ToArray());
            }
      

  13.   


    我测试了一下:            for (int i = 0; i < 1; i++)
                {
                    Extention.CopyValuesTo<ChenWei>(ll, other);
                }就消耗了:  Time:0.057
      

  14.   

    我再举个很简单的每一个人都可以经历到的相反的例子。假设一个“日期”在一个复杂的程序中要被许多代码中使用,通常我们使用DateTime类型来声明它。但是,假设有人使用string声明了它,并且已经在这个复杂的程序中几十个重要的地方(包括循环处理搓成中)使用了它,我们一定要将它改为DateTime类型么?如果单独测试一个DateTime和string类型在处理日期相关的比较大小、参数传递、格式检查等方面的操作速度,可以说使用DateTime会比使用string速度至少高20%(甚至高数倍),但是我们将本来较复杂的程序进行这个改造之后并不能让程序速度高20%,而大概是只能得到可以忽略不计的最终效果。此时,改造与不改造的决策,并不是由只看到这一个语句的“效率差别”时的感觉来决定的,这种改造“值不值得”时这个语句的效率差别很可能已经排不到主要的矛盾因素的位置了,而是考虑很多工程因素(例如“只在必要时采取修改代码,而不是为了追求完美来写代码;每当修改代码我们会进行全面的回复回归测试,所以完成程序功能的代码只占项目开发成本的一小部分”)。
      

  15.   

    这个反射帖子中的反射及其简单。还有复杂一点的反射。如果涉及方法的Invoke操作,要比不反射直接调用通常会慢500倍甚至更高。此时是不是更加不应该使用Invoke。但是我们在.net framework中还是可以看到很多地方使用到了Invoke的,并不能因为看到了这个操作就说.net framework就整体上慢了500倍。实际上,它整体上可能比java中类似的一堆“框架”的性能高的多。这些系统中使用反射做法的“高、低”判断,是框架设计者权衡比较了各种现成的系统开发过程中的整体效果的结果,往往是从工程或者框架方便发觉有它必要的理由,并不是说使用它的人原先不知道单个语句的执行效率的差别而盲目使用它。
      

  16.   

    TO: sp1234理解大哥的意思, 绝大部份的项目, 正如大哥所说, 局部的效率不是关键因素..... 尤其是一般的公司内部应用程序, 效率和速度并不是影响项目成败的因素.....但我们目前的项目是一个大型的WEB项目, 是一种公开的网上应用, 因此对速度的要求是非常高的, 哪怕是几十毫秒的影响都要找出原因...... 因此不同的应用场景, 就会有不同的要求.....没有绝对的正确, 也没有绝对的错误, 关键是在什么角度和应用.... 我是这样理解的..... 我们都没错...