Artech

Develop every application as an art using the most suitable technologies!

常用链接

统计

积分与排名

网上邻居

我的博文系列

最新评论

[原创]深入理解C#3.x的新特性(4):Automatically Implemented Property

深入理解C#3.x的新特性系列在沉寂一个月之后,今天继续。在本系列前3部分中,我们分别讨论了Anonymous TypeExtension Method Lambda Expression,今天我们来讨论另一个实用的、有意思的New featureAutomatically Implemented Property

一、繁琐的private field + public property Definition

相信大家大家已经习惯通过一个private field + public property的发式来定义和实现一个public Property。就像下面一个Artech.AutoImpProperty. Point

namespace Artech.AutoImpProperty
{
    
public class Point
    
{
        
private double x;
        
private double y;    

        
public double X
        
{
            
get
            
{
                
return this.x;
            }

            
set
            
{
                
this.x = value;
            }

        }

        
public double Y
        
{
            
get return y; }
            
set { y = value; }
        }


        
public Point(double x, double y)
        
{
            
this.x = x;
            
this.y = y;
        }

    }

}


虽然在Property中的set/get block中,我们可以不受限制地定义我们的业务逻辑,但是在大多是场合下,我们都是像上面的code一样直接对一个定义的field进行操作:在get block中返回field的值,在set block中对field赋值。也就是说,我们大多数还是将Property作为它所对应的field的直接封装。在说道Property的定义,我顺便提一下我们定义Property的一个原则:Property中的操作应该是立即能够执行完成的,我们不应该将一些Time consuming的操作放在一个Property中。因为我曾经看到过有人把调用Web Service的操作放在Property中,这是不知的推荐的,像这样的操作应该封装在一个Method中。

把话题转到我们简单的private field + public property Definition上来。如果我们定义一个Class中,只需要定义一个这样的Property,我们通过上面的code去定义可能觉得没什么。但是如果我们的Class,尤其是作为Business EntityClass,需要封装非常多的数据,我们需要为不同类型的数据分别定义一个Property,这样不断重复的工作大家一定觉得很厌烦。虽然我们的IDE-VS 2005VS 2008 beta 2通过Encapsulate Field的方式为我们的Coding工作减轻了负担(不清楚该小技巧的朋友可以参见下图),但是能在Programming Language级别就能够去除掉这些重复的定义得花,不但从根本上使Developer得到解脱,还能使我们的程序变得更加简洁和优雅。现在我们这一点我们可以做到了。


二、没有FieldAutomatically Implemented Property Definition

C# 3.x中,借助它提供的Automatically Implemented Property新特性,我们可以从繁琐的、重复的Coding工作中解脱出来了。我们来看我们先在的Property有多简单: Artech.AutoImpProperty. Vector

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Artech.AutoImpProperty
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            Vector v 
= new Vector(12);
            Console.WriteLine(
"X = {0} and Y = {1}", v.X, v.Y);
        }

    }


    
public class Vector
    
{
        
public double X getset; }
        
public double Y getset; }

        
public Vector(double x, double y)
        
{
            
this.X = x;
            
this.Y = y;
        }

    }
    
    }

}

通过上面的Code,我们大家能够体会到Automatically Implemented Property为我们定于Property带来的价值了吧。首先Property对应的Field从跟上上省去了;在set/get我们只需要一个申明式的语句,而不在需要去实现它(Automatically Implemented)。而我们定义的Artech.AutoImpProperty. Vector和上面定义的Artech.AutoImpProperty. Point是完全等效的

三、Backing Field成就了Automatically Implemented Property

从上面我们提供的Code的对比,我们可以很直观的体会到Automatically Implemented Property的实用价值。我现在来讨论一下这样的功能在技术上是如何实现的。

如果读过本系列前面3篇文章的朋友,一定记得我经常在重复这样的观点:C#3.x仅仅是基于.NET Programming Language,而不是基于.NET Framework的。换句话说,就是.NET Programming Language对于得编译器在编译的时候给我们玩了一个“障眼法”:加了一些必要的code,使原本我们看起来显得残缺的code(比如缺少对Property 的实现)变得完整。在运行的时候,这些code和原来的code是完全一样的。

为了使大家对Automatically Implemented Property的实现有一个直观的了解,我们把基于两种不同的Property definitionClass放到一起:传统的Field-based Explicit Implemented Property V.S. Automatically Implemented Property

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Artech.AutoImpProperty
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            Vector v 
= new Vector(12);
            Console.WriteLine(
"X = {0} and Y = {1}", v.X, v.Y);
        }

    }


    
public class Vector
    
{
        
public double X getset; }
        
public double Y getset; }

        
public Vector(double x, double y)
        
{
            
this.X = x;
            
this.Y = y;
        }

    }


    
public class Point
    
{
        
private double x;
        
private double y;    

        
public double X
        
{
            
get
            
{
                
return this.x;
            }

            
set
            
{
                
this.x = value;
            }

        }

        
public double Y
        
{
            
get return y; }
            
set { y = value; }
        }


        
public Point(double x, double y)
        
{
            
this.x = x;
            
this.y = y;
        }

    }

}

现在我们先通过Reflector来看看在最终编译生成的Assembly中,Artech.AutoImpProperty. PointArtech.AutoImpProperty. Vector到底有何不同:

通过上图我们可以看到:Artech.AutoImpProperty. Point和我们在Source code定义的一致, 具有两个PropetyXY)和对应的Fieldxy)。但是对于我们通过Automatically Implemented Property方式定义的Artech.AutoImpProperty. Vetor就有点特别了:虽然在Source Code中我们只定义了两个PropertyXY),不曾对应任何的Field。但是现在却凭空多处两个Field<X>k__BackingField <Y>k__BackingField。看到这两个多出来的banking field,我们不难想象他们的作用了:他们分别对应着我们定义的两个PropertyXY),其作用和Artech.AutoImpProperty. Point中定义的两个Fieldxy)完全一样。我们可以通过在ReflectorDisassemble Artech.AutoImpProperty. Vetor查看其最终的C# Code

public class Vector
{
    
// Fields
    [CompilerGenerated]
    
private double <X>k__BackingField;
    [CompilerGenerated]
    
private double <Y>k__BackingField;

    
// Methods
    public Vector(double x, double y)
    
{
        
this.X = x;
        
this.Y = y;
    }


    
// Properties
    public double X
    
{
        [CompilerGenerated]
        
get
        
{
            
return this.<X>k__BackingField;
        }

        [CompilerGenerated]
        
set
        
{
            
this.<X>k__BackingField = value;
        }

    }


    
public double Y
    
{
        [CompilerGenerated]
        
get
        
{
            
return this.<Y>k__BackingField;
        }

        [CompilerGenerated]
        
set
        
{
            
this.<Y>k__BackingField = value;
        }

    }

}


C# 3.x相关内容:
[原创]深入理解C# 3.x的新特性(1):Anonymous Type
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part I
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part II
[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression
[原创]深入理解C# 3.x的新特性(4):Automatically Implemented Property
[原创]深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer

posted on 2007-09-15 21:07 Artech 阅读(3850) 评论(30)  编辑 收藏 网摘 所属分类: A. .NET FrameworkE. LINQ

评论

#1楼 2007-09-15 23:37 Brian Yang[未注册用户]

简单明了,抓住本质,漂亮!   回复  引用    

#2楼 2007-09-15 23:39 zhuzhubaobei[未注册用户]

这个系列不过,喜欢这种介绍底层本质的东西,希望继续保持这种风格将其他的新特性写完。   回复  引用    

#3楼[楼主] 2007-09-15 23:43 Artech      

@Brian Yang
@zhuzhubaobei
感谢对本系列的关注^_^
太抬举了,还谈不上什么风格。
  回复  引用  查看    

#4楼 2007-09-16 00:43 Anytao      

这个特性真是太爽了,刚才试了一下果然好用,.NET在语言级风格上越发让人喜欢,这种进步是难能可贵的。
说到封装属性,Automatically Implemented Property应该无法封装对字段的可靠性检查吧,如果有这方面的需求,是否还有回到传统的Field+Property方式上??
  回复  引用  查看    

#5楼[楼主] 2007-09-16 00:46 Artech      

@Anytao
不知道所说的可靠性检查具体指那些方面?
  回复  引用  查看    

#6楼 2007-09-16 01:21 Anytao      

字段封装为属性的一个很大的方面是对字段实现一定的控制作用,例如读写属性的控制,另外就是可以提供一定的可靠性,合法性检测控制。
我理解Automatically Implemented Property对读写控制是完全胜任的,但是对合法性检测等方面的需求就不一定合适,例如:
class Person
{
private string name;

public string Name
{
get { return name; }
set { name = value; }
}

private int age;
public int Age
{
get { return age; }
set
{
if ((value > 0) && (value < 200))
{
age = value;
}
else
{
throw new ArgumentOutOfRangeException("年龄有问题。");
}
}
}
}

这种需求出现的时候,可能还是要回归到Field+Property的形式来实现,是否更好?
  回复  引用  查看    

#7楼 2007-09-16 02:25 yinh      

我在想,如果c#再实现一个关键字:writeonly,与readonly相对应,是不是就不需要这种自动实现的property了?因为如果只是控制读写的话,用readonly,writeonly + field,也可以很好的实现。
除了情节之外,这种完全不做任何控制的property相比较起field来说是否已经没有意义。
  回复  引用  查看    

#8楼 2007-09-16 04:33 STS[未注册用户]

早在vs2005beta的时候已经向MS提过那个建议了.
当初的提议是这样的:
public string Name
{
get;
set
{
if(value==null)throw(new ArgumentNullException("value"));
#Name=value;
}
}

不过当时他们的回复说 : 没有意义!!
他们当时是认为snippets能帮助程序员完成那些琐碎的事情.

他们明显是后悔了, snippets根本就没人用. 写POCO的代码依然是那么痛苦.

所以现在才推出这个功能是迫不得已的. 虽然这个功能真的是不必要的.


  回复  引用    

#9楼[楼主] 2007-09-16 07:21 Artech      

@Anytao
从经过编译器编译后最终生成的代码来看,Automatically Implemented Property 根本不会添加任何额外的代码,仅仅在为Property添加一个field,并在get/set中通过简单的返回field的值以及为field赋值。不会添加任何验证逻辑。
  回复  引用  查看    

#10楼[楼主] 2007-09-16 07:26 Artech      

@yinh
我觉得Automatically Implemented Property 仅仅用在你完全把Property当成Field使用的场景。
  回复  引用  查看    

#11楼 2007-09-16 10:23 A1[未注册用户]

@STS
我的观点和你的提议相同。
如果 Automatically Implemented Property 仅仅可以:
public double X { get; set; }
那实在是鸡肋。
  回复  引用    

#12楼[楼主] 2007-09-16 10:45 Artech      

@A1
其实我的理解是,多一项选择总归是好的,聊胜于无,呵呵!
  回复  引用  查看    

#13楼 2007-09-16 16:05 Jeffrey Zhao      

@Artech
Property比Field要来得“正式”,这个特性还是很有意义的,呵呵。
  回复  引用  查看    

#14楼 2007-09-16 16:56 镜涛      

编译出的最终代码没有什么区别,只是现在的方式较以前简单。其实CLR并没有改变,后面的工作交给它实现了。   回复  引用  查看    

#15楼[楼主] 2007-09-16 17:12 Artech      

@镜涛
所以,我才一再强调,这些新的特性仅仅是Compiler的特性^_^
  回复  引用  查看    

#16楼[楼主] 2007-09-16 21:50 Artech      

@Jeffrey Zhao
不管是鸡肋也好、革新也好。我觉得一项创新能给我们带来好处,我们就该欣然接受。
  回复  引用  查看    

#17楼 2007-09-18 08:57 网魂小兵      

写的很好,听君一席话,胜读十年书啊!!!   回复  引用  查看    

#18楼 2007-09-18 09:15 菜菜45[未注册用户]

大家用过VS2005的重构功能没有?选定一个private的字段,右键选择重构,选择封装字段。大家没有vs2008的时候,也可以偷懒用下这个功能。^_^   回复  引用    

#19楼[楼主] 2007-09-18 09:32 Artech      

@网魂小兵
这句话太夸张了,呵呵^_^
  回复  引用  查看    

#20楼[楼主] 2007-09-18 09:32 Artech      

@菜菜45
我的第一张插图就是讲的Refactor呀^_^
  回复  引用  查看    

#21楼 2007-09-20 10:41 xiao_p      

要看你使用的范围,如果是想封装一定的逻辑在property里面,那就老写法,如果是单纯的field + property,那这么写还是简单不少的,其实这个特性还是很人性化的,毕竟减少了我们很多工作吗!

不过,自从用了很多代码生成器之后,倒是确实很少写这些属性什么的了。
  回复  引用  查看    

#22楼 2007-09-21 13:59 Anytao      

@Artech
这也是MS的一贯特点,方便开发,隐藏越来越多。
  回复  引用  查看    

#23楼[楼主] 2007-09-26 23:00 Artech      

@xiao_p
@Anytao
勿以善小而不为,我的观点是虽然这不是一种革新性的变化,只要它能给我们带来好处,我们就应该接受它。
  回复  引用  查看    

#24楼 2007-09-27 18:00 张子阳.      

你好~~ 我给你发了私人留言 ^O^   回复  引用  查看    

#25楼 2007-10-25 09:13 油纸伞      

大哥,你这篇随笔最上面的图片中Refactor是怎么来的,是VS新版本的功能吗?还是你安装了什么VS的插件?   回复  引用  查看    

#26楼[楼主] 2007-10-25 17:43 Artech      

@油纸伞
VS 2005自带的功能。
  回复  引用  查看    

#27楼 2008-01-17 11:26 Silent Void      

@油纸伞
@Artech
有些版本没有Refactor功能,例如Express版本...
  回复  引用  查看    

#28楼 2008-01-19 15:17 共同学习,共同进步      

C#3.x仅仅是基于.NET Programming Language,而不是基于.NET Framework的。换句话说,就是.NET Programming Language对于得编译器在编译的时候给我们玩了一个“障眼法”:加了一些必要的code,使原本我们看起来显得残缺的code(比如缺少对Property 的实现)变得完整。在运行的时候,这些code和原来的code是完全一样的。
--------------太精典了。谢谢
  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 894270




相关文章:

相关链接: