类型构造器-记一次悲惨经历,论我是如何用静态构造器来作死的

在写一个wp的论坛程序时,我定义了几个类。一个是管理类(即Manager),这个管理类不能被实例化,它管理着论坛的板块类型(PlateCategory)和板块(Plate)的集合,即

static PlatesManager() {       

   //…

   private static ObservableCollection<PlateCategory> PlateCategories;          private static ObservableCollection<Plate> Plates;        public static ObservableCollection<PlateCategory> GetPlateCategories() {             return PlateCategories;         }         public static ObservableCollection<Plate> GetPlates() {             return Plates;         }
}

当然,这没什么,很正常不过,我又想,如果每次创建一个新的Plate和PlateCategory类都要调用一下这个Manager类的Add方法,感觉好像很麻烦,于是我就在Plate和PlateCategory的构造方法和析构方法中添加了如下代码:

        public PlateCategory() {
            PlatesManager.AddPlateCategory(this);
        }

        ~PlateCategory() {
            PlatesManager.RemovePlateCategory(this);
        }

这个还好,我也自我感觉良好。不过比较诡异的一幕要发生了,我不知怎么地居然还想弄一个仓库类,觉得这样比较又逼格。于是创建了IRepository接口,并创建了两个仓库PlateRepository和PlateCategoryRepository。接口定义了增删改查操作:

public interface IRepository<T> {
        IEnumerable<T> GetAll();
        T Get(T t);
        T Get(int id);
        T Add(T t);
        bool Remove(T t);
        bool Remove(int id);
        bool Update(T t);
}

然后我把这两个仓库添加到了Manager管理类中,并写下了静态构造器,也成为类型构造器以及增删改查:

public class PlatesManager {

        static PlatesManager() {
            PlateRepo = PlateRepository.GetInstance();
            PlateCateRepo = PlateCategoryRepository.GetInstance();

            PlateCategories = PlateCateRepo.GetAll() as ObservableCollection<PlateCategory>;
            Plates = PlateRepo.GetAll() as ObservableCollection<Plate>;

            PlateCategories = new ObservableCollection<PlateCategory>() {
                new PlateCategory{Name="手机"},
                new PlateCategory{Name="电脑"},
                new PlateCategory{Name="手表"},
            };
            Plates = new ObservableCollection<Plate>() {
                new Plate("WP",PlateCategories[0]),
                new Plate("IOS",PlateCategories[0]),
                new Plate("Android",PlateCategories[0])
            };
        }

        public static void AddPlate(Plate plate) {
            PlateRepo.Add(plate);
        }

        public static void AddPlateCategory(PlateCategory plateCategory) {
            PlateCateRepo.Add(plateCategory);
        }

        public static bool RemovePlate(Plate plate) {
            return PlateRepo.Remove(plate);
        }

        public static bool RemovePlateCategory(PlateCategory category) {
            return PlateCateRepo.Remove(category);
        }

        public static bool RemovePlate(int fid) {
            return PlateRepo.Remove(fid);
        }

        public static bool RemovePlateCategory(int id) {
            return PlateCateRepo.Remove(id);
        }

        private static IRepository<Plate> PlateRepo;
        private static IRepository<PlateCategory> PlateCateRepo;

}

看起来是不是一切over,但当我运行代码时,神奇的一幕出现了,抛出了一个TypeInitializationException异常,于是我找了很久错误,依然不知道什么原因,最后我翻开Jeff大神的CLR via C#,找到了静态构造方法的相关描述。

静态构造器会在第一次被调用时执行,也就是我调用Manager类时,Manager的静态方法开始执行,即初始化数据Plates集合和PlateCategories集合。执行这个任务时,静态构造器会调用一个线程和锁来确保数据不可被其他线程写,但这时,Plate和PlateCategory的构造器却调用了Manager类的Add方法,然而,Manager类是被锁起来的!因为他还没有被初始化完毕,所以就导致CLR抛出了一个异常,程序终止。5555~

然而,我为什么还要把仓库类给帮出来呢?好像并没有这个类什么事情,但其实并不是这样的。其实这个死并没有这么简单就作完。不过要表达的东西说完了,就不讲下去了,我才不会告诉你其实我一开始是在仓库中初始化数据呢╮( ̄▽ ̄)╭

献上哥特萝莉sama照片一张。。。

时间: 2024-10-10 02:25:06

类型构造器-记一次悲惨经历,论我是如何用静态构造器来作死的的相关文章

CLR静态构造器

CLR保证一个类型构造器在每个AppDomain中只执行一次,而且这种执行是线程安全的. 作用: 就是初始化静态成员 比如有几个静态成员需要初始化那你把初始化代码放到哪呢? 放到普通构造函数里,那肯定不行.因为静态成员没有创建实例就要可用. 专门建一个static public方法来初始化?这样用起来非常不方便,你需要在“第一次”使用静态成员前先调用这个方法.如果你在使用静态成员前忘了调用该方法,会导致错误.如果重复调用,又是冗繁操作. 所以静态构造函数就派上用场了.它会在你第一次调用静态成员(

记大一大二经历以及教训

2017  5.10   我目前就读川大本科大二,第一篇文章,纯属个人的大学生活感想.   大一青涩,现在想来可以用无知形容,没找到笃定前行的方向,然而厌恶了现在的专业--风景园林.以下吐槽.此专业在我川真的是巨水,本身国内没多少开这个专业的,2012教育部学科评估排名倒数,在一个985院校里面的专业连个普通一本都比不上,可想而知教学质量和教学环境.何况这个专业挂名工科,实则是搞艺术的,数学物理一概不学,和工科不沾边,要我觉得不喜欢设计千万不要选这种专业,身边动辄就从小开始画画,素描水彩不在话下

职业生涯手记——记人生中第一次经历的产品上线——内测篇Day1

2017/08/11 产品内测期Day1 公司经过这几天的各种讨论会,终于订出了一个产品上线前内测活动方案,然后今天还算是顺利启动了,也可以算是可喜可贺: 临下班前,今天已经有79人申请内测,其中25人成功安装了APP. 作为我个人来讲,还真是人生中第一次参与内测,很难得的经历:而且公司里的高层和中层们以前都是做项目类型的,几乎都没有APP内测的经历呢. 今天一整天客服组的妹纸们真是忙,我就没见过她们站起来活动,甚至是喝水和上厕所,一定都在与内测用户解答问题呢.路过她们电脑前看到与用户的聊天记录

编译第一个内核模块的悲惨经历

今天编译自己的第一个内核模块但是出现错误,结果如下: 而我的Makefile 和C文件是这样的: 开始的时候,我以为是Makefile写错了,尤其是"obj-m :=",这个我改了好几遍,网上的各种写法都用过,比如: obj-m :=memdev.o                        #要生成的模块名 memdevmodule-objs:=module               #生成这个模块名所需要的目标文件 使用之后编译结果还是错误,找了别人写的被确认正确的Makef

【转】记毕业季的求职经历

原文地址:http://www.cnblogs.com/chkkch/p/3401015.html        (mark一下,打基础做准备!) Accept的公司:Facebook, DeNA, SAP, Intel, ARMFail的公司:阿里巴巴,腾讯,百度,Google,微软,平安科技,豆瓣,雅虎,Amazon,NVIDIA,EMC,VMware,还有各种说不上名字的小公司 今年(确切的说是从去年暑假开始)的工作实在不好找.随着国内的经济形势下降,公司的招的人也随之下降得厉害.腾讯,阿

[SPM_hw1]记一次项目经历

最近一次做的比较完整的项目开发是上学期末的web大作业. 项目的基本要求是做一个通缉犯管理系统.其中包括了可以对于用户进行操作的后台管理员部分,以及可以进行通缉信息查询和添加举报信息的前台界面.从项目开始到deadline大概有2周左右的时间.当然,由于仅仅是作为期末的大作业,并没有涉及到什么预算之类的问题,开发中涉及的技术都是通过网络进行学习以及搜索的. 开发中使用的语言是JAVA,IDE用的是Intellij IDEA,使用了java web开发的spring mvc框架,前台页面使用了bo

记一次性能优化经历

提到这次性能优化,好简单,仅仅是压缩了一下显示图片大小, 网页打开速度得到了显著的提升,抛砖引玉吧. 优化前 优化后: 在优化前,一次产品列表要显示12张图片,每张图片在600kb左右,也就是每打开一次当前页面需要传输7.2mb左右的图片文件,压缩后,每一张图片在12kb左右,每次传输200kb,由此可见,降低网络传输量,可以显著提升网页浏览速度,采用小图片,压缩css,压缩js,把js放到一个文件中,这些都是减少网络传输途径.

记一次爬虫经历

一个同学想要提取某网站的数据,然后导出为excel. 刚开始,我在网上找了一个php生成excel的demo,名字叫PHPExcel. 刚开始我是直接从那个网站上读数据,然后利用那个demo导出为excel,但是遇到了一个特别坑的问题—— 那个网站服务器实在太差了,我要从那里读1400多个网页的内容,经常出现读取失败的问题,然后程序就进行不下去了. 于是,想到办法1: 每次读取5页数据,最后可以生成大概1400/5个表. 这样每次读取失败,再重新运行程序读取. 但是有可以改进的地方—— 那个网站

kali 安装最新firefox的悲惨经历

最新的的firefox用的是量子内核,在windows上面的确感觉相比之前的firefox快了好多 想把kali 2017虚拟机的也替换掉 按照步骤: 1 添加源: /etc/apt/sources.list deb http://downloads.sourceforge.net/project/ubuntuzilla/mozilla/apt all main 2 添加认证 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com C12