constants & start readonly & share的区别(整理自网络&msdn)
2009-11-28 17:37
316 查看
一。const型表达式的值在编译时形成,而static readonly表达式的值直到程序运行时才形成。
有时你不想在在程序运行时改变域,如运行时程序依靠的数据文件,一个math类的pi值,或者任何在程序运行时你不想改变的值。为了处理这种情况,c#中定义了两个近似的、相关的成员类型:contants和read-only域。
Constants域
从字面可以看出,常数(用关键字const表示)在应用程序运行期间保持不变。当定义某个事物为const时记住两个规则:第一,定义成常数的成员的值是在编译时设置的——或者是由编程者指定,或者是由编译器设置缺省值;第二,一个常数成员的值必须被写为一个字面常数。
为了定义一个常数域,在要定义的成员前使用一个const关键字,如下所示:
using System;
class MagicNumbers
{
public const double pi = 3.1415;
public const int answerToAllLifesQuestions = 42;
}
class ConstApp
{
public static void Main()
{
Console.WriteLine("pi = {0}, everything else = {1}",
MagicNumbers.pi, MagicNumbers.answerToAllLifesQuestions);
}
}
请注意这个代码的一个关键点——不必在客户端实例化MagicNumbers类,因为const成员缺省是静态的。为了更清楚的展示它,我们列出这两个域在MSIL中生成时的情况:
answerToAllLifesQuestions : public static literal int32 = int32(0x0000002A)
pi : public static literal float64 = float64(3.1415000000000002)
Read-only 域
使用const域是非常有用的,因为他清楚的表明了编程者的意图。然而,这只能用于在编译时已经知道值的情况下。所以,当一个域只有在运行时才能知道值而且一旦初始化以后值便不能改变的情况下,编程者该怎么办呢?C#语言的设计者用Read-only域的办法解决了这个问题(在其他语言中一般不会处理)。
当你用readonly关键字定义了一个域时,你只能在一个地方设置这个域的值——构造函数。以后,域的值便不能被自身类或者使用这个类的客户改变。让我们看一个图形应用程序记录屏幕分辨率的例子。你不能用const处理这个问题,因为应用程序直到运行时才能确定终端用户的屏幕分辨率,所以你必须使用这样的代码:
using System;
class GraphicsPackage
{
public readonly int ScreenWidth;
public readonly int ScreenHeight;
public GraphicsPackage()
{
this.ScreenWidth = 1024;
this.ScreenHeight = 768;
}
}
class ReadOnlyApp
{
public static void Main()
{
GraphicsPackage graphics = new GraphicsPackage();
Console.WriteLine("Width = {0}, Height = {1}",
graphics.ScreenWidth,
graphics.ScreenHeight);
}
}
猛一看,这个代码正是我们需要的。然而,还有一点小问题:我们定义的readonly域是一个实例域,这意味着是用户在使用域之前必须先实例化类。这可能也不是什么问题,甚至这正是你想做的——在实例化类的时候正可以初始化readonly域的值。但如果你想要一个被定义成静态的、能在运行时被初始化的常数时该怎么办呢?这时,我们可以定义一个带static和readonly修饰符的域。然后,创建一个构造函数的特殊类型——static constructor。静态函数可以用来初始化static域、readonly域或其他的域。现在我们改变先前的例子,给屏幕分辨率域加上static和readonly,并且增加一个静态构造函数。
using System;
class GraphicsPackage
{
public static readonly int ScreenWidth;
public static readonly int ScreenHeight;
static GraphicsPackage()
{
// Code would be here to
// calculate resolution.
ScreenWidth = 1024;
ScreenHeight = 768;
}
}
class ReadOnlyApp
{
public static void Main()
{
Console.WriteLine("Width = {0}, Height = {1}",
GraphicsPackage.ScreenWidth,
GraphicsPackage.ScreenHeight);
}
}
二。何时使用 Shared
共享类或结构的成员使每个实例都可以使用该成员,而不必让每个实例保留自己的副本。例如,如果一个变量的值应用于整个应用程序,这点很有用。如果声明该变量为 Shared,那么所有实例会访问相同的存储位置,而如果一个实例更改了变量值,所有实例都会访问更新后的值。
规则
声明上下文。只能在模块级使用 Shared。这意味着 Shared 元素的声明上下文必须为一个类、结构或模块,而不能是源文件、命名空间或过程。
组合修饰符。不能在同一声明中将 Shared 与 Overrides、Overridable、NotOverridable、MustOverride 或 Static (Visual Basic) 同时指定。
访问。通过用类或结构名称而不是类或结构的特定实例的变量名称限定一个共享元素来访问它。您甚至不必创建类或结构的实例就可以访问它的共享成员。
下面的示例调用由 Double 结构所公开的共享过程 IsNaN。
If Double.IsNaN(result) Then MsgBox("Result is mathematically undefined.")
隐式共享。您无法在 Const 语句 (Visual Basic) 中使用 Shared 修饰符,但常数会被隐式共享。同样,您无法将模块或接口的成员声明为 Shared,但它们会被隐式共享。
行为
存储。共享变量或事件只能在内存中存储一次,而无论您创建多少个它的类或结构的实例。同样,共享过程或属性仅存储一组局部变量。
通过实例变量进行访问。可以通过用包含类或结构的特定实例的变量名称限定一个共享元素来访问它。虽然这通常会按预期设想起作用,但编译器会生成一条警告消息,并使访问通过类或结构名称而不是变量来进行。
通过实例表达式进行访问。通过返回类或结构实例的表达式访问共享元素时,编译器会使访问通过类或结构名称而不是计算表达式来进行。如果您要表达式执行其他操作以及返回实例,将产生意外结果。下面的示例演示这一点。
复制代码
Sub main()
shareTotal.total = 10
' The preceding line is the preferred way to access total.
Dim instanceVar As New shareTotal
instanceVar.total += 100
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of through
' the variable instanceVar. This works as expected and adds
' 100 to total.
returnClass().total += 1000
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of calling
' returnClass(). This adds 1000 to total but does not work as
' expected, because the MsgBox in returnClass() does not run.
MsgBox("Value of total is " & CStr(shareTotal.total))
End Sub
Public Function returnClass() As shareTotal
MsgBox("Function returnClass() called")
Return New shareTotal
End Function
Public Class shareTotal
Public Shared total As Integer
End Class
在前面的示例中,编译器在代码通过实例访问共享变量 total 时两次都生成警告消息。每次它都使访问直接通过类 shareTotal 来进行,而不利用任何实例。在特意调用过程 returnClass 的情况下,意味着它甚至不会生成对 returnClass 的调用,因此不会执行显示“Function returnClass() called”的额外操作。
Shared 修饰符可用于下面的上下文中:
Dim 语句
Event 语句
Function 语句
运算符语句
Property 语句
Sub 语句
有时你不想在在程序运行时改变域,如运行时程序依靠的数据文件,一个math类的pi值,或者任何在程序运行时你不想改变的值。为了处理这种情况,c#中定义了两个近似的、相关的成员类型:contants和read-only域。
Constants域
从字面可以看出,常数(用关键字const表示)在应用程序运行期间保持不变。当定义某个事物为const时记住两个规则:第一,定义成常数的成员的值是在编译时设置的——或者是由编程者指定,或者是由编译器设置缺省值;第二,一个常数成员的值必须被写为一个字面常数。
为了定义一个常数域,在要定义的成员前使用一个const关键字,如下所示:
using System;
class MagicNumbers
{
public const double pi = 3.1415;
public const int answerToAllLifesQuestions = 42;
}
class ConstApp
{
public static void Main()
{
Console.WriteLine("pi = {0}, everything else = {1}",
MagicNumbers.pi, MagicNumbers.answerToAllLifesQuestions);
}
}
请注意这个代码的一个关键点——不必在客户端实例化MagicNumbers类,因为const成员缺省是静态的。为了更清楚的展示它,我们列出这两个域在MSIL中生成时的情况:
answerToAllLifesQuestions : public static literal int32 = int32(0x0000002A)
pi : public static literal float64 = float64(3.1415000000000002)
Read-only 域
使用const域是非常有用的,因为他清楚的表明了编程者的意图。然而,这只能用于在编译时已经知道值的情况下。所以,当一个域只有在运行时才能知道值而且一旦初始化以后值便不能改变的情况下,编程者该怎么办呢?C#语言的设计者用Read-only域的办法解决了这个问题(在其他语言中一般不会处理)。
当你用readonly关键字定义了一个域时,你只能在一个地方设置这个域的值——构造函数。以后,域的值便不能被自身类或者使用这个类的客户改变。让我们看一个图形应用程序记录屏幕分辨率的例子。你不能用const处理这个问题,因为应用程序直到运行时才能确定终端用户的屏幕分辨率,所以你必须使用这样的代码:
using System;
class GraphicsPackage
{
public readonly int ScreenWidth;
public readonly int ScreenHeight;
public GraphicsPackage()
{
this.ScreenWidth = 1024;
this.ScreenHeight = 768;
}
}
class ReadOnlyApp
{
public static void Main()
{
GraphicsPackage graphics = new GraphicsPackage();
Console.WriteLine("Width = {0}, Height = {1}",
graphics.ScreenWidth,
graphics.ScreenHeight);
}
}
猛一看,这个代码正是我们需要的。然而,还有一点小问题:我们定义的readonly域是一个实例域,这意味着是用户在使用域之前必须先实例化类。这可能也不是什么问题,甚至这正是你想做的——在实例化类的时候正可以初始化readonly域的值。但如果你想要一个被定义成静态的、能在运行时被初始化的常数时该怎么办呢?这时,我们可以定义一个带static和readonly修饰符的域。然后,创建一个构造函数的特殊类型——static constructor。静态函数可以用来初始化static域、readonly域或其他的域。现在我们改变先前的例子,给屏幕分辨率域加上static和readonly,并且增加一个静态构造函数。
using System;
class GraphicsPackage
{
public static readonly int ScreenWidth;
public static readonly int ScreenHeight;
static GraphicsPackage()
{
// Code would be here to
// calculate resolution.
ScreenWidth = 1024;
ScreenHeight = 768;
}
}
class ReadOnlyApp
{
public static void Main()
{
Console.WriteLine("Width = {0}, Height = {1}",
GraphicsPackage.ScreenWidth,
GraphicsPackage.ScreenHeight);
}
}
二。何时使用 Shared
共享类或结构的成员使每个实例都可以使用该成员,而不必让每个实例保留自己的副本。例如,如果一个变量的值应用于整个应用程序,这点很有用。如果声明该变量为 Shared,那么所有实例会访问相同的存储位置,而如果一个实例更改了变量值,所有实例都会访问更新后的值。
规则
声明上下文。只能在模块级使用 Shared。这意味着 Shared 元素的声明上下文必须为一个类、结构或模块,而不能是源文件、命名空间或过程。
组合修饰符。不能在同一声明中将 Shared 与 Overrides、Overridable、NotOverridable、MustOverride 或 Static (Visual Basic) 同时指定。
访问。通过用类或结构名称而不是类或结构的特定实例的变量名称限定一个共享元素来访问它。您甚至不必创建类或结构的实例就可以访问它的共享成员。
下面的示例调用由 Double 结构所公开的共享过程 IsNaN。
If Double.IsNaN(result) Then MsgBox("Result is mathematically undefined.")
隐式共享。您无法在 Const 语句 (Visual Basic) 中使用 Shared 修饰符,但常数会被隐式共享。同样,您无法将模块或接口的成员声明为 Shared,但它们会被隐式共享。
行为
存储。共享变量或事件只能在内存中存储一次,而无论您创建多少个它的类或结构的实例。同样,共享过程或属性仅存储一组局部变量。
通过实例变量进行访问。可以通过用包含类或结构的特定实例的变量名称限定一个共享元素来访问它。虽然这通常会按预期设想起作用,但编译器会生成一条警告消息,并使访问通过类或结构名称而不是变量来进行。
通过实例表达式进行访问。通过返回类或结构实例的表达式访问共享元素时,编译器会使访问通过类或结构名称而不是计算表达式来进行。如果您要表达式执行其他操作以及返回实例,将产生意外结果。下面的示例演示这一点。
复制代码
Sub main()
shareTotal.total = 10
' The preceding line is the preferred way to access total.
Dim instanceVar As New shareTotal
instanceVar.total += 100
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of through
' the variable instanceVar. This works as expected and adds
' 100 to total.
returnClass().total += 1000
' The preceding line generates a compiler warning message and
' accesses total through class shareTotal instead of calling
' returnClass(). This adds 1000 to total but does not work as
' expected, because the MsgBox in returnClass() does not run.
MsgBox("Value of total is " & CStr(shareTotal.total))
End Sub
Public Function returnClass() As shareTotal
MsgBox("Function returnClass() called")
Return New shareTotal
End Function
Public Class shareTotal
Public Shared total As Integer
End Class
在前面的示例中,编译器在代码通过实例访问共享变量 total 时两次都生成警告消息。每次它都使访问直接通过类 shareTotal 来进行,而不利用任何实例。在特意调用过程 returnClass 的情况下,意味着它甚至不会生成对 returnClass 的调用,因此不会执行显示“Function returnClass() called”的额外操作。
Shared 修饰符可用于下面的上下文中:
Dim 语句
Event 语句
Function 语句
运算符语句
Property 语句
Sub 语句
相关文章推荐
- const和static readonly的区别
- 整理:CString类的完美总结&&CString 成员函数用法大全&&string 与 CString 转化&&<string><string.h> 和<cstring>的区别
- Fix SharePoint 2013 Site in Read only mode after an interrupted backup
- VMWare 的三种网络模式的区别
- 转: const和static readonly的区别
- AT&T汇编格式与Intel汇编格式区别(根据由尚德视频教程整理)
- const和static readonly的区别
- java -jar start.jar和nohup java -jar xxx.jar > test.log &的区别
- oracle表空间&用户创建整理(来源于网络)
- ASP.NET中TextBox控件设置ReadOnly="true"后台取不到值
- C# FAQ: const和static readonly有什么区别?
- readonly & const
- vue报错: Cannot assign to read only property 'exports' of object '#<Object>'
- NAT对于网络上的其它人都不可见(但可以转发端口),Bridged和网络里的其它物理机没区别,Internal只能在虚拟机之间可见,Host-only只对主机可见(最符合我的服务器需求),最多可设置8块网卡实现混杂
- C#中静态常量(const)和动态常量(static readonly)的一些区别
- "网管师"与"网管员"和 "网络工程师"的区别
- 【HTML】input readonly&nbsp…
- C# static readonly 与 const 的区别
- Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definitio
- VMware三种网络模式根本区别 bridged nat host-only