首页 新闻 会员 周边

请问这个方法为什么调用次数一多,就报栈溢出的异常?

0
悬赏园豆:20 [已解决问题] 解决于 2015-05-12 14:46

为了验证实体对象的属性值是否合法,其实就是验证各字段的MaxLength,Range,Required等属性标签,我在Model父类中写了这个方法,代码如下,

 /// <summary>
        /// 验证实体的数据是否符合要求
        /// </summary>
        /// <param name="p">被验证的实体</param>
        /// <returns>符合返回true</returns>
        public static bool IsValid(this Parent p)
        {
            try
            {
                var context = new ValidationContext(p, null, null);
                var results = new List<ValidationResult>();
                TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(p.GetType()), p.GetType());

                bool isValid = Validator.TryValidateObject(p, context, results, true);
                return isValid;
            }
            finally
            {
                GC.Collect();
            }
            
        }

 

我还特意加了个finally,在每次调用完成都强制垃圾回收..

可是调用这个方法次数一多,就报下边这个异常了,大约在9030到9050次之间就会出这个异常..

 

我的测试代码如下:

Item_Prop是Parent的子类.

 

你可能会问,干嘛要调用这么多次...

好吧,其实我在BaseDAO里写了一个TransInsert(List<Parent> list){}的方法,

这个方法用于向数据库中批量插入一批实体数据.

在foreach   list时,对每个item进行IsValid()验证...于是,list项一多就出现上边的异常了..

 

同一个list中,item超9030之后就会出现这个异常了,

 

还有一种情况是,我有多个list..

list<SubClass1> listA

list<SubClass2>listB

list<SubClassN>listN

 

即使每个list中的项不到9000,只有100到500项,分别将这多个(N个)list插入时,也会出现那个异常...

 

我总结了一下,就是IsValid()方法调用次数一多,就会报那个异常...

 

请问这个方法为什么会导致这个异常?怎么解决?谢谢!

 

 

开始我还以为是插入到数据库中的时候出了问题呢..后来将这句注释掉之后就正常了.

问题补充:

Parent,Item_Cat的类结构如下 :

 

Parent

using System;
using System.Collections;
using SoEasy.Common;
using System.Data;

namespace SoEasy.Model.BaseEntity
{
    /// <summary>
    /// 实体父类
    /// </summary>
    [Serializable]
    public abstract class Parent
    {
        /// <summary>
        /// 保存所有字段与属性的映射关系
        /// </summary>
        private IList lst = new ArrayList();

        /// <summary>
        /// 是否存在某字段映射关系
        /// 返回:true:存在,false:不存在
        /// </summary>
        /// <param name="fieldName">字段名称</param>
        private bool IsExistsField(string fieldName)
        {
            bool flag = false;
            for (int i = 0; i < lst.Count; i++)
            {
                Hashtable ht = lst[i] as Hashtable;
                if (ht != null && ht[Constant.STR_KEY].Equals(fieldName))
                {
                    flag = true;
                    break;
                }
            }
            return flag;
        }

        /// <summary>
        /// 设定字段与属性的映射关系
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <param name="value">字段值</param>
        protected void SetFieldMapping(string fieldName, object value)
        {
            if (!IsExistsField(fieldName))
            {
                Hashtable ht = new Hashtable();
                ht.Add(Constant.STR_KEY, fieldName);
                ht.Add(Constant.STR_VALUE, value);
                lst.Add(ht);
            }
        }

        /// <summary>
        /// 计算已设定值的字段数
        /// </summary>
        /// <returns></returns>
        public int CountFields()
        {
            return lst.Count;
        }

        /// <summary>
        /// 得到指定位置的列名
        /// </summary>
        /// <param name="index">保存列的索引</param>
        /// <returns></returns>
        public string ColumnName(int index)
        {
            string name = "";
            if (lst.Count > index)
            {
                Hashtable ht = lst[index] as Hashtable;
                if (ht != null)
                {
                    name = ht[Constant.STR_KEY].ToString();
                }
            }
            return name;
        }

        /// <summary>
        /// 得到指定某列处保存的值
        /// </summary>
        /// <param name="index">保存列的索引</param>
        /// <returns></returns>
        public object ColumnValue(int index)
        {
            object obj = null;
            if (lst.Count > index)
            {
                Hashtable ht = lst[index] as Hashtable;
                if (ht != null)
                {
                    obj = ht[Constant.STR_VALUE];
                }
            }
            return obj;
        }

        /// <summary>
        /// 非=号的查询限制条件
        /// </summary>
        public NotEqualCondition OtherCondition { get; set; }

        /// <summary>
        /// 获取GUID
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public string GetGuid()
        {
            return Guid.NewGuid().ToString();
        }


        /// <summary>
        /// 映射表名及主键字段信息
        /// 子类必需实现该方法
        /// </summary>
        /// <returns></returns>
        public abstract Hashtable MappingTableInfo();

        /// <summary>
        /// 将DataTable中的首行数据转成对应的实体对象
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <returns>返回实体对象,null表示转换失败</returns>
        abstract public Parent GetModelFromDataTable(DataTable dt);
        
    }
}

 

Item_Cat 类

using System;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using SoEasy.Model.BaseEntity;
using SoEasy.Common;
using System.Data;


namespace Model
{
    /// <summary>
    /// 分类表
    /// </summary>
    [Serializable]
    public class Item_Cat : Parent
    {
        public override System.Collections.Hashtable MappingTableInfo()
        {
            Hashtable ht = new Hashtable();
            ht.Add(Constant.STR_DB_TABLE, "item_cat");
            ht.Add(Constant.STR_DB_PK, "CID");
            return ht;
        }
        public override Parent GetModelFromDataTable(DataTable dt)
        {
            Item_Cat x = null;
            if (dt != null && dt.Rows.Count > 0)
            {
                x = new Item_Cat();
                DataRow dr = dt.Rows[0];
                x.Cid = long.Parse(dr["Cid"].ToString());
                x.Name = dr["Name"].ToString();
                x.Parentcid = long.Parse(dr["Parentcid"].ToString());
                x.Isparent = int.Parse(dr["Isparent"].ToString());
                x.Sort_Num = long.Parse(dr["Sort_Num"].ToString());
                x.Is_Enable = int.Parse(dr["Is_Enable"].ToString());
                x.Creater_Id = dr["Creater_Id"].ToString();
                x.Create_Time = DateTime.Parse(dr["Create_Time"].ToString());
                x.Updater_Id = dr["Updater_Id"].ToString();
                x.Update_Time = DateTime.Parse(dr["Update_Time"].ToString());

            }
            return x;
        }



        long cid;

        /// <summary>
        ///分类ID
        /// </summary>
        public long Cid
        {
            get { return cid; }
            set { cid = value; SetFieldMapping("Cid", value); }
        }


        string name;

        /// <summary>
        ///分类名称
        /// </summary>
        [MaxLength(100)]
        public string Name
        {
            get { return name; }
            set { name = value; SetFieldMapping("Name", value); }
        }


        long parentcid;

        /// <summary>
        ///父分类ID
        /// </summary>
        public long Parentcid
        {
            get { return parentcid; }
            set { parentcid = value; SetFieldMapping("Parentcid", value); }
        }


        int isparent;

        /// <summary>
        ///是否是父分类
        /// </summary>
        public int Isparent
        {
            get { return isparent; }
            set { isparent = value; SetFieldMapping("Isparent", value); }
        }


        long sort_num;

        /// <summary>
        ///排序号
        /// </summary>
        public long Sort_Num
        {
            get { return sort_num; }
            set { sort_num = value; SetFieldMapping("Sort_Num", value); }
        }


        int is_enable;

        /// <summary>
        ///是否启用
        /// </summary>
        public int Is_Enable
        {
            get { return is_enable; }
            set { is_enable = value; SetFieldMapping("Is_Enable", value); }
        }


        string creater_id;

        /// <summary>
        ///
        /// </summary>
        [MaxLength(36)]
        public string Creater_Id
        {
            get { return creater_id; }
            set { creater_id = value; SetFieldMapping("Creater_Id", value); }
        }


        DateTime create_time;

        /// <summary>
        ///
        /// </summary>
        public DateTime Create_Time
        {
            get { return create_time; }
            set { create_time = value; SetFieldMapping("Create_Time", value); }
        }


        string updater_id;

        /// <summary>
        ///
        /// </summary>
        [MaxLength(36)]
        public string Updater_Id
        {
            get { return updater_id; }
            set { updater_id = value; SetFieldMapping("Updater_Id", value); }
        }


        DateTime update_time;

        /// <summary>
        ///
        /// </summary>
        public DateTime Update_Time
        {
            get { return update_time; }
            set { update_time = value; SetFieldMapping("Update_Time", value); }
        }



    }
}

测试方法:

 static void InsertTest()
        {
            List<Parent> ll = new List<Parent>();
            Item_Prop c = new Item_Prop();
            c.Cid = 23;
            for (int i = 0; i <10000; i++)
            {
                
                c.IsValid();
              //  ll.Add(c);
            }
            //bl.TransInsert(ll);
        }

 

扩展类:

using SoEasy.Common;
using SoEasy.Model.BaseEntity;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;

namespace SoEasy.Model.BaseEntity
{
    public static class ModelExtension
    {
        /// <summary>
        /// 将实体类转成表(实体类的属性要赋值后才能转)
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static DataTable ToDataTable(this Parent p)
        {
            DataTable dt = new DataTable();
            for (int i = 0; i < p.CountFields(); i++)
            {
                dt.Columns.Add(new DataColumn(p.ColumnName(i), p.ColumnValue(i).GetType()));
            }
            DataRow dr = dt.NewRow();
            for (int i = 0; i < p.CountFields(); i++)
            {
                dr[i] = p.ColumnValue(i);
            }
            dt.Rows.Add(dr);
            return dt;
        }
        /// <summary>
        /// 验证实体的数据是否符合要求
        /// </summary>
        /// <param name="p">被验证的实体</param>
        /// <returns>符合返回true</returns>
        public static bool IsValid(this Parent p)
        {
            try
            {
                var context = new ValidationContext(p, null, null);
                var results = new List<ValidationResult>();
                TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(p.GetType()), p.GetType());

                bool isValid = Validator.TryValidateObject(p, context, results, true);
                return isValid;
            }
            finally
            {
                
            }
            
        }

        /// <summary>
        /// 将DataTable转换成T类型的实体对象
        /// </summary>
        /// <typeparam name="T">T类必须继承自Parent类</typeparam>
        /// <param name="dt">DataTable数据源</param>
        /// <param name="throwException">出现异常时是否抛出</param>
        /// <returns>T类实体对象,null表示转换失败</returns>
        public static T GetTModel<T>(this DataTable dt, bool throwException = false) where T : Parent, new()
        {
            return ExceptionHelper.ExceptionRecord(() =>
            {

                T t = null;
                try
                {
                    t = new T();
                    t = (T)t.GetModelFromDataTable(dt);
                }
                catch (Exception ex)
                {
                    t = null;
                    throw new Exception("将DataTable转换成实体类时发现异常:" + ex.Message, ex);
                }
                return t;
            }, throwException);
        }
    }
}

 

整体就这样了.

hexllo的主页 hexllo | 菜鸟二级 | 园豆:318
提问于:2015-05-11 16:41
< >
分享
最佳答案
0

先把 GC.Collect(); 去掉试试

收获园豆:18
dudu | 高人七级 |园豆:30994 | 2015-05-11 17:36

试过了,开始就没加GC.Collect();的.

后来发现加了没用,也删掉了.

还是没解决..麻烦再帮我想想吧

hexllo | 园豆:318 (菜鸟二级) | 2015-05-11 17:59

@hexllo: 问题可能出在你是针对同一个Item_Prop实例进行大量的调用,你可以将创建Item_Prop实例的代码放在循环中试试。

dudu | 园豆:30994 (高人七级) | 2015-05-11 18:08

@dudu: 试过了,我向一个List中Add 1000000个 new Item_Cat都没有报错.

hexllo | 园豆:318 (菜鸟二级) | 2015-05-12 08:30

@hexllo: 提问中的stack overflow是一种正常情况。如果你想一探究竟,需要了解一下方法调用时的call stack机制(推荐阅读:函数调用过程探究)以及.NET CLR中的stack walking原理(推荐阅读:Stackwalking in the CLR)。

dudu | 园豆:30994 (高人七级) | 2015-05-12 09:57

@dudu: 看了一下,还是不明白为什么这个方法会出异常..而其它方法重复调用不会,这个方法里的代码有什么特殊之处吗?

在我印象中只有无限递归时才会出现StackOverflow的异常啊...

hexllo | 园豆:318 (菜鸟二级) | 2015-05-12 10:19

@hexllo: 可以将这个方法中的代码一行一行注释进行测试,看是不是某行代码引起的?

dudu | 园豆:30994 (高人七级) | 2015-05-12 10:22

@hexllo: 另外,可以试试在 GC.Collect(); 之后加上下面的代码:

GC.WaitForPendingFinalizers();
dudu | 园豆:30994 (高人七级) | 2015-05-12 13:43

@dudu: 您说对了!!!

是这行看起来很复杂的代码引起的:

TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(p.GetType()), p.GetType());

 

不过不知道为什么它会引发StackOverflow,总之,很感谢!

hexllo | 园豆:318 (菜鸟二级) | 2015-05-12 14:45
其他回答(2)
0

古人说过一个名言:

What Andy gives, Bill takes away。

真是有道理。不过改成

What Andy gives, Programmer takes away。

应该更准确一些。

爱编程的大叔 | 园豆:30839 (高人七级) | 2015-05-11 17:00

哥们,认真是种态度!

支持(0) 反对(0) hexllo | 园豆:318 (菜鸟二级) | 2015-05-11 17:13
0

哎…… 肯定 是注释掉这一行代码有问题嘛 ,但是你只上传了极小的一部分代码, 只字片言,断章取义,我们是想破脑袋也不知道你的代码哪里有问题啊?

收获园豆:2
需要格局 | 园豆:2145 (老鸟四级) | 2015-05-11 17:57

呵呵,提供的就是出现问题的代码呀,

放一大堆上来反而不好找.

我非常确定是IsValid()方法的问题.

不调用它就不出异常了..

 

支持(0) 反对(0) hexllo | 园豆:318 (菜鸟二级) | 2015-05-11 18:00

@hexllo: 关键是你上传的方法,还有好几个类啊?这几个类是什么意思?怎么定义的?你不上传我们不知道啊?

支持(0) 反对(0) 需要格局 | 园豆:2145 (老鸟四级) | 2015-05-11 18:06

@田麦成: 嗯,我把这些类都放上去了,麻烦帮我看一下吧,谢谢了

支持(0) 反对(0) hexllo | 园豆:318 (菜鸟二级) | 2015-05-12 08:39
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册