亲而有间,密而有疏;和而不同,美美与共

C#小知识点积累

1、sealed 修饰符

概念

C#提出了一个密封类(sealed class)的概念,帮助开发人员来解决这一问题。 密封类在声明中使用sealed 修饰符,这样就可以防止该类被其它类继承。如果试图将一个密封类作为其它类的基类,C#将提示出错。理所当然,密封类不能同时又是抽象类,因为抽象总是希望被继承的。 sealed(C# 参考) sealed 修饰符可以应用于类、实例方法和属性。密封类不能被继承。密封方法会重写基类中的方法,但其本身不能在任何派生类中进一步重写。当应用于方法或属性时,sealed 修饰符必须始终与 override(C# 参考) [ http://msdn2.microsoft.com/zh-cn/library/ebca9ah3(VS.80).aspx ] 一起使用。

用途

目前本人只在单例模式中运用过这个修饰符:

首先对单例模式进行个简单的描述(本人的理解,有误请指出):第1点要求:保证了一个类有且只能有一个实例。

这样一来,我们就应想到,要想调用这个类里面的非静态方法时候,再也不能用我们熟悉的 Class c = new Class();来先实例化,再去点点点~

如下面这个例子,我们在Test方法里写了点东西,我们要想去调用这个方法,既然没法正常的实例化,那么就想个其他的办法。也就是说这个类得给我们提供一个访问它的全局访问点。

这就是单例模式的第2点要求,如例子中的GetInstance();具体实现,代码很简单,相信大家都能看懂。

public sealed class IndexManager
    {
        #region 单例模式之饿汉模式 能保证了在整个应用程序运行周期只创建一次实例(GetInstance方法来获得实例instance)
        private readonly static IndexManager instance = new IndexManager();
        private IndexManager()
        { 
        
        }
        /// <summary>
        /// 整个单例模式的全局访问点
        /// </summary>
        /// <returns></returns>
        public static IndexManager GetInstance()
        {
            return instance;
        }
        #endregion
        
        public void Test()
        {...}  
}

2、设计表的时候,Id设置为GUID类型比自增长类型 在数据插入的时候要来得速度快。

因为自增长还要在先去统计原有的数据量,再加上锁,去更新。对于一些非关系型表的设计中,可以考虑用GUID类型的主键Id。

如:搜索模块中的关键词统计。

3、Quarzt简介,第三方定时任务框架

 

4、单纯觉得Chorme的Cookie管理界面好舒服

5、跨线程操作控件

winform中,经常遇到界面假死问题,所以我们很有可能使用开启一个后台线程来解决,然后在后台线程中若要操作某些控件,而这些控件创建是在主线程进行的,系统就会报错。幸好,可以使用Control.Invoke或者Control.BeiginInvoke方法来解决。

 

      private static void StartThread()
        {
            Thread myThread = new Thread(AddLayer3D);
            myThread.IsBackground = true;
            myThread.Start();
        }
      
        private static void AddLayer3D()
        {
        dynamic test = ...;
            kmlTreeView.Invoke(new DeleGEControlInvoke(GETreeControlInvoke), new object[] { test });//test为参数
        }

        private delegate void DeleGEControlInvoke(dynamic test);//定义一个与要执行操作的方法签名相同的委托
        private static void GETreeControlInvoke(dynamic test)
        {
            kmlTreeView.ParseKmlObject(test);//这里的kmlTreeView即为我们这个例子的控件
        }

 6、C#中if与#if区别

今天(2016/2/25)第一次看到这个语句:

#if DEBUG
throw new Exception("竹子在调试");//如果你在看源码,想看一个完整的过程,请在Release下看
#endif

这个代码在Debug(调试)的时候会执行,而在Release的时候(VS中启动按钮边上有选择启动,Debug还是Release)就变“灰”,相当于就是注释了。

有些程序在调试、兼容性、平台移植等情况下可能想要通过简单地设置一些参数就生成一个不同的软件,这当然可以通过变量设置,把所有可能用到的代码都写进去,在初始化时配置,但在不同的情况下可能只用到一部分代码,就没必要把所有的代码都写进去,就可以用条件编译,通过预编译指令设置编译条件,在不同的需要时编译不同的代码。

觉得很神奇(可能也反映了我本身底子不扎实,毕竟自学...这么想也不好,碰到用到才学,这才是正确的对于浩瀚的编程知识学习方式),就上网查了下。拖两篇软文过来

 1 if的作用是程序流控制,会直接编译、执行。
 2 #if是对编译器的指令,其作用是告诉编译器,有些语句行希望在条件满足时才编译。
 3 
 4 --------------------------------------------------------------------------------------------------------------------
 5 
 6 #if 使您可以开始条件指令,测试一个或多个符号以查看它们是否计算为 true。如果它们的计算结果确实为 true,则编译器将计算位于 #if 与最近的 #endif 指令之间的所有代码。例如,
 7 
 8  
 9 复制
10 #define DEBUG
11 // ...
12 #if DEBUG
13     Console.WriteLine("Debug version");
14 #endif
15 可以使用运算符 ==(相等)、!=(不相等)、&&(与)及 ||(或)来计算多个符号。还可以用括号将符号和运算符分组。
16 
17 备注
18 使用 #if 以及 #else、#elif、#endif、#define 和 #undef 指令,可以包括或排除基于由一个或多个符号组成的条件的代码。这在编译调试版本的代码或编译特定配置时最为有用。
19 
20#if 指令开始的条件指令必须用 #endif 指令显式终止。
21 
22 #define 使您可以定义一个符号,通过将该符号用作传递给 #if 指令的表达式,使该表达式计算为 true。
23 
24 也可以用 /define 编译器选项来定义符号。可以用 #undef 来取消定义符号。
25 
26 用 /define 或 #define 定义的符号与具有同一名称的变量不冲突。即,不应将变量名传递到预处理器指令,并且只能用预处理器指令计算符号。
27 
28#define 创建的符号的范围是在其中定义该符号的文件。
29 
30 示例
31  
32 复制
33 // preprocessor_if.cs
34 #define DEBUG#define VC_V7
35 using System;
36 public class MyClass 
37 {
38     static void Main() 
39     {
40 #if (DEBUG && !VC_V7)
41         Console.WriteLine("DEBUG is defined");
42 #elif (!DEBUG && VC_V7)
43         Console.WriteLine("VC_V7 is defined");
44 #elif (DEBUG && VC_V7)
45         Console.WriteLine("DEBUG and VC_V7 are defined");
46 #else
47         Console.WriteLine("DEBUG and VC_V7 are not defined");
48 #endif
49     }
50 }
51 输出
52 DEBUG and VC_V7 are defined
View Code

这篇就更为详尽点

  1 有些程序在调试、兼容性、平台移植等情况下可能想要通过简单地设置一些参数就生成一个不同的软件,这当然可以通过变量设置,把所有可能用到的代码都写进去,在初始化时配置,但在不同的情况下可能只用到一部分代码,就没必要把所有的代码都写进去,就可以用条件编译,通过预编译指令设置编译条件,在不同的需要时编译不同的代码。
  2 (一)条件编译方法
  3  条件编译是通过预编译指令来实现的,主要方法有:
  4 1#if, #elif, #else, #endif
  5 #if 条件 1
  6  代码段 1
  7 #elif 条件 2
  8    代码段 2
  9 ...
 10 #elif 条件 n
 11  代码段 n
 12 #else
 13  代码段 n+1
 14 #endif
 15 即可以设置不同的条件,在编译时编译不同的代码,预编译指令中的表达式与C语言本身的表达式基本一至如逻辑运算、算术运算、位运算等均可以在预编译指令中使用。之所以能够实现条件编译是因为预编译指令是在编译之前进行处理的,通过预编译进行宏替换、条件选择代码段,然后生成最后的待编译代码,最后进行编译。
 16 #if 的一般含义是如果#if 后面的常量表达式为true,则编译它所控制的代码,如条件1成立时就代码段1,条件1不成立再看条件2是否成立,如果条件2成立则编译代码段2,否则再依次类推判断其它条件,如果条件1-N都不成力则会编译最后的代码段n+1。
 17 2、#ifdef, #else, #endif或#ifndef, #else, #endif
 18     条件编译的另一种方法是用#ifdef与#ifndef命令,它们分别表示“如果有定义”及“如果无定义”。有定义是指在编译此段代码时是否有某个宏通过 #define 指令定义的宏,#ifndef指令指找不到通过 #define 定义的某宏,该宏可以是在当前文件此条指令的关面定义的,也可以是在其它文件中,但在此指令之前包含到该文件中的。
 19 #ifdef的一般形式是:
 20 #ifdef macro_name
 21 代码段 1
 22 #else
 23 代码段 2
 24 #endif
 25  26 #ifdef的一般形式是:
 27 #ifndef macro_name
 28 代码段 2
 29 #else
 30 代码段 1
 31 #endif
 32 这两段代码的效果是完全一样的。
 33 3、通过宏函数defined(macro_name)
 34 参数为宏名(无需加""),如果该macro_name定义过则返回真,否则返回假,用该函数则可以写比较复杂的条件编译指令如
 35 #if defined(macro1) || (!defined(macro2) && defined(macro3))...#else...#endif(二)条件编译技巧与示例(1)#ifdef和#defined()比较  首先比较一下这两种方法,第一种方法只能判断一个宏,如果条件比较复杂实现起来比较烦锁,用后者就比较方便。如有两个宏MACRO_1,MACRO_2只有两个宏都定义过才会编译代码段A,分别实现如下:#ifdef MACRO_1#ifdef MACRO_2代码段 A#endif#endif
 36 或者
 37 #if defined(MACRO_1) && defined(MACRO_2)
 38 #endif
 39 同样,要实现更复杂的条件用#ifdef更麻烦,所以推荐使用后者,因为即使当前代码用的是简单的条件编译,以后在维护、升级时可能会增加,用后者可维护性较强。旧的编译器可能没有实现#defined()指令,C99已经加为标准。要兼容老的编译器,还需用#ifdef指令。
 40 2、#if与 #ifdef或#if defined()比较
 41   比如自己写了一个printf函数,想通过一个宏MY_PRINTF_EN实现条件编译,用#if可实现如下
 42 #define MY_PRINTF_EN 1
 43 #if MYS_PRINTF_EN == 1
 44  int printf(char* fmt, char* args, ...)
 45 { ...
 46 }
 47 #endif
 48 如果宏MY_PRINTF_EN定义为1则编译这段代码,如果宏定义不为1或者没有定义该宏,则不编译这段代码。同样也可以通过#ifdef或者#defined()实现,如
 49 #define MY_PRINTF_EN 1
 50 #if defined(MY_PRINTF_EN)
 51  int printf(char* fmt, char* args, ...)
 52 { ...
 53 }
 54 #endif
 55 在这种情况下两种方法具有异曲同工之妙,但试想如果你为了节约代码写了两个printf函数,在不同情况下使用不同的printf函数,一个是精简版一个是全功能标准版,如:
 56 #define MY_PRINTF_SIMPLE
 57  
 58 #ifdef MY_PRINTF_SIMPLE
 59    void printf(*str) // 向终端简单地输出一个字符串
 60 {...
 61 }
 62 #endif
 63 #ifdef MY_PRINTF_STANDARD
 64  int printf(char* fmt, char* args, ...)
 65 {...
 66 } 
 67 #endif
 68 同样可以用#if defined()实现
 69 #define MY_PRINTF_SIMPLE
 70  
 71 #if defined(MY_PRINTF_SIMPLE)
 72    void printf(*str) // 向终端简单地输出一个字符串
 73 {...
 74 }
 75 #elif defined(MY_PRINTF_STANDARD)
 76  int printf(char* fmt, char* args, ...)
 77 {...
 78 } 
 79 #endif
 80 两种方法都可以实现,但可见后者更方便。但试想如果你有三个版本,用前者就更麻烦了,但方法相似,用后者就更方便,但仍需三个宏进行控制,你要住三个宏,改进一下就用#if可以用一个宏直接控制N种情况如:
 81 #define MY_PRINTF_VERSION     1
 82  
 83 #if MY_PRINTF_VERSION == 1
 84    void printf(*str) // 向终端简单地输出一个字符串
 85 {...
 86 }
 87 #elif MY_PRINTF_VERSION == 2
 88  int printf(char* fmt, char* args, ...)
 89 {...
 90 } 
 91 #elif MY_PRINTF_VERSION == 3
 92 int printf(unsigned char com_number, char* str)
 93 {
 94 }
 95 #else
 96 默认版本
 97 #endif
 98 这样,你只需修改一下数字就可以完成版本的选择了
 99 看来好像用#if 比较好了,试想如下情况:你写了一个配置文件叫做config.h用来配置一些宏,通过这些宏来控制代码,如你在config.h的宏
100 #define MY_PRINTF_EN 1
101 来控制是否需要编译自己的printf函数,
102 而在你的源代码文件printf.c中有如下指令
103 #i nclude "config.h"
104 #if MY_PRINTF_EN == 1
105  int printf(char* fmt, char* args, ...)
106 { ...
107 }
108 #endif
109 但这样也会有一个问题,就是如果你忘了在config.h中添加宏MY_PRINTF_EN,那么自己写的printf函数也不会被编译,有些编译器会给出警告:MY_PRINTF_EN未定义。如果你有两个版本的想有一个默认版本,可以在printf.c中这样实现
110 #incldue "config.h"
111 #if !defined(MY_PRINTF_VERSION)
112   #define MY_PRINTF_VERSION   1               
113 #endif
114 #if MY_PRINTF_VERSION == 1
115    void printf(*str) // 向终端简单地输出一个字符串
116 {...
117 }
118 #elif MY_PRINTF_VERSION == 2 
119  int printf(char* fmt, char* args, ...)
120 {...
121 } 
122 #elif MY_PRINTF_VERSION == 3
123 int printf(unsigned char com_number, char* str)
124 {
125 }
126 #endif
127 这种情况下还得用到#ifdef或#if defined(),你可以不用动主体的任何代码,只需要修改printf.c文件中MY_RPINTF_VERSION宏的数字就可以改变了,如果用前面那种方法还得拖动代码,在拖动中就有可能造成错误。
128 再试想,如果软件升级了,或者有了大的改动,原来有三个版本,现在只剩下两个版本了,如
129 #if MY_PRINTF_VERSION == 2 
130  int printf(char* fmt, char* args, ...)
131 {...
132 } 
133 #elif MY_PRINTF_VERSION == 3
134 int printf(unsigned char com_number, char* str)
135 {
136 }
137 #endif
138 因为这些核心代码不想让使用这些代码的人关心,他们只需要修改config.h文件,那就要在printf.c中实现兼容性。如果以前有人在config.h配置宏MY_PRINTF_VERSION为1,即有
139 #define MY_PRINTF_VERSION   1
140 而现在没有1版本了,要想兼容怎么办?那当然可以用更复杂的条件实现如:
141 #if MY_PRINTF_VERSION == 2 || MY_PRINTF_VERSION == 1 
142  int printf(char* fmt, char* args, ...)
143 {...
144 } 
145 #elif MY_PRINTF_VERSION == 3
146 int printf(unsigned char com_number, char* str)
147 {
148 }
149 #endif
150 不过还有另外一种方法,即使用#undef命令
151 #if MY_PRINTF_VERSION == 1
152   #undef MY_PRINTF_VERSION
153   #define MY_PRINTF_VERSION  2
154 #endif
155 #if MY_PRINTF_VERSION == 2 
156  int printf(char* fmt, char* args, ...)
157 {...
158 } 
159 #elif MY_PRINTF_VERSION == 3
160 int printf(unsigned char com_number, char* str)
161 {
162 }
163 #endif
164 用#if还有一个好处,如果你把宏名记错了,把MY_PRINTF_EN定义成了MY_PRINT_EN,那么你用#ifdef MY_PRINTF_EN或者#if defined(MY_PRINTF_EN)控制的代码就不能被编译,查起来又不好查,用#if MY_PRINTF_EN ==1控制就很好查,因为你把MY_PRINTF_EN定义成MY_PRINT_EN,则MY_PRINTF_EN实际上没有定义,那么编译器会给出警告#if MY_PRINTF_EN == 1中的MY_PRINTF_EN没有定义,但错就比较快。
View Code

  7、驰骋工作流简介

今天看到一个新的名词,驰骋工作流,这好奇心又上来了,这又是什么鬼~

开源的驰骋工作流引擎简介

    驰骋工作流引擎研发与2003年,具有.net与java两个版本,它们代码结构、数据库结构、设计思想、功能组成、操作手册完全相同。流程表单模版两个版本完全通用。

   CCFlow是.net版本的简称,由济南团队负责研发。JFlow是在java版本的简称,由深圳研发团队研发。两款产品核心代码向社会100%开源,十多年来,我们一直践行自己的诺言,努力提高产品质量,真心服务中国IT产业,成为了国内知名的老牌工作流引擎,在国内    开源BPM领域稳坐第一位。

  驰骋工作流引擎操作简单、概念通俗易懂、操作手册完善(计:14万字)、代码注释完整、案例丰富翔实、单元测试覆盖面广。

  驰骋工作流引擎包含表单引擎与流程引擎两大部分,并且两块完美结合,协同高效工作。流程与表单界面可视化的设计,可配置程度高,适应于中国国情的多种场景的需要。

  驰骋工作流引擎发展与2003年,历经十多年的发展,在国内拥有最广泛的研究群体与应用客户群,是大型集团企业IT部门、软件公司、研究院、高校研究与应用的产品。

  驰骋工作流引擎不仅仅能够满足中小企业的需要,也能满足通信级用户的应用,先后在西门子、海南航空、中国船舶、陕汽重卡、山东省国土资源厅、华电国际、江苏测绘院、厦门证券、天津港等国内外大型企业政府单位服役。

  ccbpm拥有完整的解决方案:ccform表单引擎、ccgpm权限管理系统、ccsso单点登录系统、ccoa驰骋OA、CCIM即时通讯(能够满足20万人同时在线).以上的解决方案除ccim以外都是开源的一体化的解决方案。

  ccbpm方便与您的开发框架集成,与第三方组织机构集成. 既有配置类型的开发适用于业务人员,IT维护人员, 也有面向程序员的高级引擎API开发。

OSchina上的截图:

 

查了下组团培训要12万元,人数不限,所以很多人都在“拉帮结派”,共分摊这12万,来去参加培训~

8、文件名不能相同,类名可以相同

今天操作EF的时候,想着创建一个Model中某个类的部分类(partial),系统却一直报错:

 

觉得很奇怪,为何在业务层创建Bll的部分类的时候就可以呢?

原来是因为文件名或文件夹名有重复了不行,不是类名的原因。

解决:

  新建个文件夹,在这个文件夹中创建部分类,这样一来就解决文件重名的问题,那么由于要跟T4生成的模型类同步,要求命名空间要一致,手动改下新建部分类的命名空间,Perfect!

这里的Cart.cs,我估计就跟ModelPartical的等级一样,属于文件或文件夹范畴。报错的重名应该就是跟这个重名。

9、VS2015令人激动的一些新功能:

Shared Project 集成

http://www.tuicool.com/articles/beaMZv3

五个难以置信的VS2015新特性

http://www.codeceo.com/article/5-vs-2015-preview-features.html

10、为何没有win9:老外说:“789。”   我来翻译下:seven ate(eight) nine

   我大天朝:七把(八)九食。

  哈哈,有会心一笑吗。

11、C# ToString()方法一些特殊用法 

一、取中文日期显示
1、年月日时分 currentTime.ToString("f"); //不显示秒
2、年月 currentTime.ToString("y");
3、月日 currentTime.ToString("m");
4、格式为:2003-9-23 currentTime.ToString("d");
5、格式为:14:24 currentTime.ToString("t");
二、字符型转换 转为字符串

12345.ToString("n"); //结果:12,345.00
12345.ToString("C"); //结果:¥12,345.00
12345.ToString("e"); //结果:1.234500e+004
12345.ToString("f4"); //结果:12345.0000
12345.ToString("x"); //结果:3039 (16进制)
12345.ToString("p"); //结果:1,234,500.00%

 

12、yield 关键字向编译器指示它所在的方法是迭代器块。编译器生成一个类来实现迭代器块中表示的行为。在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值。这是一个返回值,例如,在 foreach 语句的每一次循环中返回的值。yield 关键字也可与 break 结合使用,表示迭代结束。

例子:
yield return <expression>;
yield break;

在 yield return 语句中,将计算 expression 并将结果以值的形式返回给枚举器对象;expression 必须可以隐式转换为 yield 类型的迭代器。

在 yield break 语句中,控制权将无条件地返回给迭代器的调用方,该调用方为枚举器对象的 IEnumerator.MoveNext 方法(或其对应的泛型System.Collections.Generic.IEnumerable<T>)或 Dispose 方法。

yield 语句只能出现在 iterator 块中,这种块可作为方法、运算符或访问器的主体实现。这类方法、运算符或访问器的体受以下约束的控制:

  • 不允许不安全块。

  • 方法、运算符或访问器的参数不能是 ref 或 out

  • yield return 语句不能放在 try-catch 块中的任何位置。该语句可放在后跟 finally 块的 try 块中。

  • yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。

yield 语句不能出现在匿名方法中。有关更多信息,请参见匿名方法(C# 编程指南)

当和 expression 一起使用时,yield return 语句不能出现在 catch 块中或含有一个或多个 catch 子句的 try 块中。

public class List
{
    //using System.Collections;
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;//不用yield的话,就得自己构建个迭代器,也就是定义个集合来接收这些返回值,返回集合。
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}
/*
Output:
2 4 8 16 32 64 128 256 
*/

 

 

tip:日积月累,小知识也能构建成一份不错的谈资。玩笑了,慢慢更新,日常能够用到,又不是很容易引起大家注意的点,争取都放到本文中。

posted @ 2016-02-19 19:09  大兄弟竹子  阅读(1192)  评论(0编辑  收藏  举报