ike_li

耐住寂寞

博客园 首页 新随笔 联系 订阅 管理
  90 Posts :: 176 Stories :: 33 Comments :: 1 Trackbacks

公告

2011年10月31日 #

装箱(Boxing):值类型->引用类型,把一个值类型数据放到堆上,就需要装箱操作.

拆箱(Unboxing):引用类型->值类型,把一个放在堆上的值类型数据取出来,则需要进行拆箱操作.

 

值类型(原类型(SbyteByteShortUshortIntUintLongUlongCharFloatDoubleBoolDecimal)、枚举(enum)、结构(struct);

值类型数据是分配在栈中.

引用类型(类,接口,数组,委托,字符串等);引用类型数据分配在堆上.

 

例如,对于如下简单的装箱和拆箱操作语句。

int i = 123;
object obj = i;//Boxing
if( obj is int )
int j = (int) obj;//Unboxing

 装箱和拆箱存在的意义:值类型是数据的容器,它存储在堆栈上,不具备多态性,而.NET框架在整个对象层次的设计中,使用System.Object作为所有类型的基类,但是Obejct是引用类型,而作为值类型的基类System.ValueType,是从System.Object派生出来的,这就产生了矛盾,装箱和拆箱就是为了解决这两种类型之间的差异。

    装箱会将一个值类型放入一个未具名类型(untyped)的引用对象中,从而允许该值类型应用于那些只能使用引用类型的场合。拆箱则会从前面的装箱对象中提取出一个值类型的副本。装箱和拆箱都是比较耗时的操作。

    装箱操作会将值类型转换为一个引用类型,这个过程中会创建一个新的引用独享,然后将其分配到堆上,同时值类型的副本会被存储在该引用对象内部。当我们需要从装箱对象中获取任何信息时,会创建值类型的一个副本,然后将其返回。其中的关键是:当我们需要引用类型时,会创建一个新的引用类型的对象并将其放入到堆中;当我们需要访问已经装箱的对象信息时,就会创建对应值类型的一个副本,并将其返回。

    装箱和拆箱最大的问题是它们会自动发生。当我们使用的是值类型,而期望的是引用类型,那么编译器就会自动产生装箱和拆箱语句。

   我们来看下面的语句,居然也发生了装箱和拆箱操作。

 

Console.WriteLine("A few numbers:{0}, {1}, {2}",
25, 32, 50);

    上述代码之所以发生了装箱,是因为WriteLine方法需要的参数类型是System.Object,而25是一个int类型,属于值类型,因此需要装箱,而在WriteLine方法内部实现时,需要调用方法参数的ToString()方法,为了调用装箱对象的方法,就会发生拆箱的操作。

 

    为了避免装箱和拆箱,可以将上述代码进行如下修改。

 

Console.WriteLine("A few numbers:{0}, {1}, {2}",
25.ToString(), 32.ToString(), 50.ToString());

    另外,由于装箱和拆箱都会产生新的实例,那么有时会产生一些诡异的bug,我们来查看下面的代码。

 

 

代码
1 public struct Person
2 {
3 private string _Name;
4
5 public string Name
6 {
7 get
8 {
9 return _Name;
10 }
11 set
12 {
13 _Name = value;
14 }
15 }
16
17 public override string ToString( )
18 {
19 Return _Name;
20 }
21 }
22
23  // Using the Person in a collection:
24 ArrayList attendees = new ArrayList( );
25 Person p = new Person( "Old Name" );
26 attendees.Add( p );
27
28 // Try to change the name:
29 // Would work if Person was a reference type.
30 Person p2 = (( Person )attendees[ 0 ] );
31 p2.Name = "New Name";
32
33 // Writes "Old Name":
34 Console.WriteLine(
35 attendees[ 0 ].ToString( ));

    上述代码中,Person是一个值类型,在将其放入ArrayList时,会进行装箱操作,这时会有一次复制操作,当我们需要获得ArrayList内Person对象的信息时,需要一次拆箱,又会有一次复制操作,因此,当我们并没有对ArrayList内的对象进行修改,而是针对副本进行修改。

 

    我们可以通过以下的方式来修改上述代码存在的问题。

 

代码
1 public interface IPersonName
2 {
3 string Name
4 {
5 get; set;
6 }
7 }
8
9 struct Person : IPersonName
10 {
11 private string _Name;
12
13 public string Name
14 {
15 get
16 {
17 return _Name;
18 }
19 set
20 {
21 _Name = value;
22 }
23 }
24
25 public override string ToString( )
26 {
27 return _Name;
28 }
29 }
30
31 // Using the Person in a collection:
32 ArrayList attendees = new ArrayList( );
33 Person p = new Person( "Old Name" );
34 attendees.Add( p ); // box
35
36 // Try to change the name:
37 // Use the interface, not the type.
38 // No Unbox needed
39 (( IPersonName )attendees[ 0 ] ).Name = "New Name";
40
41 // Writes "New Name":
42 Console.WriteLine(
43 attendees[ 0 ].ToString( )); // unbox
44
45

    装箱后的引用类型实现了原来值类型对象上所有的接口,这意味着不会再发生复制,但是当我们调用IPersonName.Name属性时,它会将调用请求转发给“箱子”内部的值类型,在值类型上实现接口使我们可以访问”箱子“的内部,从而允许直接改变ArrayList中的信息。

 

 

   总之,我们应该对任何将值类型转换为System.Object或者接口类型的构造保持密切的关注,例如将值类型放入集合中,在值类型上调用System.Object定义的方法等,这些操作都会将值类型转换为System.Object,只要有可能,我们都应该避免这种转换。

 

 使用微软自带ildasm.exe工具反汇编程序,可以清楚看到装箱和拆箱。


 

 


 


 

 

posted @ 2011-10-31 14:08 ike_li 阅读(15) 评论(0) 编辑

2011年8月1日 #

 /// <summary>
        
/// 移除指定菜单
        
/// </summary>
        
/// <param name="menuName">菜单名字</param>
        private void RemoveMenu(string menuName)
        {

            
foreach (ToolStripMenuItem item in menuStrip.Items)
            {
                
if ((string)item.Text == menuName)// “恢复默认大小”菜单项
                {
                    
//menuStrip.Items.Remove(item);//移除菜单项
                    menuStrip.Items.Remove(item.DropDownItems[0]);//移除菜单项
                    
//item.Visible = false; //不显示
                    item.DropDownItems[0].Visible = false;
                    
break;
                }
            }

        }
posted @ 2011-08-01 15:03 ike_li 阅读(26) 评论(0) 编辑

2011年5月24日 #

1.解压缩

没有发现修改解压缩后文件的名字方法,间接方法用 Directory.Move(filePath, newFilePath);

  /// <summary>
        
/// 利用 WinRAR 进行解压缩
        
/// </summary>
        
/// <param name="rarSourceDir">解压文件地址目录</param>
        
/// <param name="rarSaveDir">将要解压缩的 .rar 文件的存放目录(绝对路径)</param>
        
/// <param name="rarName">将要解压缩的 .rar 文件名(包括后缀)</param>
        
/// <param name="password">解压密码</param>
        
/// <returns>true 或 false。解压缩成功返回 true,反之,false。</returns>
        public static bool UnCompressRAR(string rarSourceDir, string rarSaveDir, string rarName,string password)
        {
            
bool flag = false;
            
string rarExe;
            RegistryKey regKey;
            Object regValue;
            
string cmd;
            ProcessStartInfo startinfo;
            Process process;
            
try
            {
                regKey 
= Registry.ClassesRoot.OpenSubKey(@"Applications\WinRAR.exe\shell\open\command");
                regValue 
= regKey.GetValue("");
                rarExe 
= regValue.ToString();
                regKey.Close();
                rarExe 
= rarExe.Substring(1, rarExe.Length - 7);
                
if (!Directory.Exists(rarSaveDir))
                {
                    Directory.CreateDirectory(rarSaveDir);
                }
                
//解压缩命令,相当于在要压缩文件(rarName)上点右键 ->WinRAR->解压到当前文件夹
                if (password!= "")
                {                 
                    cmd 
= string.Format("x -p{0} {1} {2}  -y", password, rarName, rarSaveDir);
                }
                
else
                {
                    cmd 
= string.Format("x {0} {1} -y", rarName, rarSaveDir);
                
                }
                startinfo 
= new ProcessStartInfo();
                startinfo.FileName 
= rarExe;
                startinfo.Arguments 
= cmd;
                startinfo.WindowStyle 
= ProcessWindowStyle.Hidden;
                startinfo.WorkingDirectory 
= rarSourceDir;
                process 
= new Process();
                process.StartInfo 
= startinfo;
                process.Start();
                process.WaitForExit();
                
if (process.HasExited)
                {
                    flag 
= true;
                }
                process.Close();
            }
            
catch (Exception e)
            {
                
throw e;
            }
            
return flag;
        }

 

posted @ 2011-05-24 14:18 ike_li 阅读(38) 评论(0) 编辑

2011年5月4日 #

 public void DrivePrint(string filePath)
        {
            
string pdfPath = filePath;
            System.Drawing.Printing.PrintDocument pd 
= new System.Drawing.Printing.PrintDocument();
            Process processInstance 
= new Process();
            ProcessStartInfo startInfo 
= new ProcessStartInfo();
            startInfo.UseShellExecute 
= true;
            startInfo.Verb 
= "Print";
            startInfo.CreateNoWindow 
= true;
            startInfo.WindowStyle 
= ProcessWindowStyle.Hidden;
            startInfo.Arguments 
= @"/p /h \" + pdfPath + "\" \"" + pd.PrinterSettings.PrinterName + " \"";
            startInfo.FileName 
= pdfPath;
            processInstance.StartInfo 
= startInfo;
            processInstance.Start();
            processInstance.CloseMainWindow();
        }
posted @ 2011-05-04 15:42 ike_li 阅读(29) 评论(0) 编辑

2010年11月29日 #

1.设置窗体属性ShowInTaskbar=false

2.加notifyicon控件notifyicon1,为控件notifyicon1的属性icon添加一个icon图标。
3.添加触发事件

代码
 //窗体最小化
        private void FrmMain_SizeChanged(object sender, EventArgs e)
        {
              
if(this.WindowState==FormWindowState.Minimized) 
              {
                  
this.Visible = false;
                  
this.WindowState = FormWindowState.Minimized;
                  
this.notifyIcon1.Visible = true;
              }
        }
        
        
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            
if (this.WindowState == FormWindowState.Normal)
            {
                
this.notifyIcon1.Visible = true;
            }
            
else
            {
                
this.Visible = true;
                
this.WindowState = FormWindowState.Normal;
                
this.notifyIcon1.Visible = false;
            }
        }
       
private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            
this.notifyIcon1.Visible = false;
        }    

 


4.可以给notifyicon添加右键菜单:

主窗体中拖入一个contextmenu控件contextmenu1,点中控件,在上下文菜单中添加菜单,notifyicon1的contextmenu行为中选中contextmenu1作为上下文菜单。


posted @ 2010-11-29 10:55 ike_li 阅读(60) 评论(0) 编辑

2010年11月16日 #

    该文被密码保护。
posted @ 2010-11-16 18:46 ike_li 阅读(4) 评论(0) 编辑

2010年11月15日 #

    该文被密码保护。
posted @ 2010-11-15 15:41 ike_li 阅读(0) 评论(0) 编辑

    该文被密码保护。
posted @ 2010-11-15 15:37 ike_li 阅读(0) 评论(0) 编辑

    该文被密码保护。
posted @ 2010-11-15 15:36 ike_li 阅读(0) 评论(0) 编辑

    该文被密码保护。
posted @ 2010-11-15 15:33 ike_li 阅读(0) 评论(0) 编辑

仅列出标题  下一页
ike_li