请给我解释一下静态构造函数的用法。为什么,什么时候我们要创建一个静态构造函数,它是否可能重载一个?
当前回答
当静态字段相互依赖,初始化顺序很重要时,静态构造函数也非常有用。如果您通过一个改变字段顺序的格式化器/美化器运行代码,那么您可能会发现自己在意想不到的地方得到了空值。
示例:假设我们有这样一个类:
class ScopeMonitor
{
static string urlFragment = "foo/bar";
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
}
当您访问fullUr时,它将是“http://www.example.com/foo/bar”。
几个月后,您将清理代码并按字母顺序排列字段(假设它们是一个更大的列表的一部分,因此您没有注意到问题)。你有:
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
static string urlFragment = "foo/bar";
}
你的fullUrl值现在只是“http://www.example.com/”,因为urlFragment在设置fullUrl时还没有初始化。不好的。所以,你添加一个静态构造函数来处理初始化:
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl;
static string urlFragment = "foo/bar";
static ScopeMonitor()
{
fullUrl= firstPart + urlFragment;
}
}
现在,不管字段的顺序是什么,初始化总是正确的。
其他回答
静态构造函数只调用创建的类的第一个实例。并用于执行在类的生命周期中只需要执行一次的特定操作。
当静态字段相互依赖,初始化顺序很重要时,静态构造函数也非常有用。如果您通过一个改变字段顺序的格式化器/美化器运行代码,那么您可能会发现自己在意想不到的地方得到了空值。
示例:假设我们有这样一个类:
class ScopeMonitor
{
static string urlFragment = "foo/bar";
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
}
当您访问fullUr时,它将是“http://www.example.com/foo/bar”。
几个月后,您将清理代码并按字母顺序排列字段(假设它们是一个更大的列表的一部分,因此您没有注意到问题)。你有:
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
static string urlFragment = "foo/bar";
}
你的fullUrl值现在只是“http://www.example.com/”,因为urlFragment在设置fullUrl时还没有初始化。不好的。所以,你添加一个静态构造函数来处理初始化:
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl;
static string urlFragment = "foo/bar";
static ScopeMonitor()
{
fullUrl= firstPart + urlFragment;
}
}
现在,不管字段的顺序是什么,初始化总是正确的。
可以使用静态构造函数初始化静态字段。在使用这些字段之前,它在一个不确定的时间运行。微软的文档和许多开发人员警告说,类型上的静态构造函数会带来巨大的开销。为了获得最佳性能,最好避免使用静态构造函数。 更新:你不能在同一个类中使用多个静态构造函数,但是你可以使用(最多)一个静态构造函数的其他实例构造函数。
为什么以及什么时候创建静态构造函数?
使用静态构造函数的一个特殊原因是创建一个“超级枚举”类。这里有一个(简单的,做作的)例子:
public class Animals
{
private readonly string _description;
private readonly string _speciesBinomialName;
public string Description { get { return _description; } }
public string SpeciesBinomialName { get { return _speciesBinomialName; } }
private Animals(string description, string speciesBinomialName)
{
_description = description;
_speciesBinomialName = speciesBinomialName;
}
private static readonly Animals _dog;
private static readonly Animals _cat;
private static readonly Animals _boaConstrictor;
public static Animals Dog { get { return _dog; } }
public static Animals Cat { get { return _cat; } }
public static Animals BoaConstrictor { get { return _boaConstrictor; } }
static Animals()
{
_dog = new Animals("Man's best friend", "Canis familiaris");
_cat = new Animals("Small, typically furry, killer", "Felis catus");
_boaConstrictor = new Animals("Large, heavy-bodied snake", "Boa constrictor");
}
}
你会非常相似地(在语法外观上)使用任何其他枚举:
Animals.Dog
与常规枚举相比,它的优点是可以轻松封装相关信息。一个缺点是不能在switch语句中使用这些值(因为它需要常量值)。
来自微软文档 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
静态构造函数(c#编程指南)
静态构造函数用于初始化任何静态数据,或执行只需要执行一次的特定操作。在创建第一个实例或引用任何静态成员之前自动调用它。
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}
讲话
静态构造函数有以下属性:
A static constructor doesn't take access modifiers or have parameters. A class or struct can only have one static constructor. Static constructors cannot be inherited or overloaded. A static constructor cannot be called directly and is only meant to be called by the common language runtime (CLR). It is invoked automatically. The user has no control on when the static constructor is executed in the program. A static constructor is called automatically. It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs before an instance constructor. A type's static constructor is called when a static method assigned to an event or a delegate is invoked and not when it is assigned. If static field variable initializers are present in the class of the static constructor, they're executed in the textual order in which they appear in the class declaration. The initializers run immediately prior to the execution of the static constructor. If you don't provide a static constructor to initialize static fields, all static fields are initialized to their default value as listed in Default values of C# types. If a static constructor throws an exception, the runtime doesn't invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain. Most commonly, a xref:System.TypeInitializationException exception is thrown when a static constructor is unable to instantiate a type or for an unhandled exception occurring within a static constructor. For static constructors that aren't explicitly defined in source code, troubleshooting may require inspection of the intermediate language (IL) code. The presence of a static constructor prevents the addition of the xref:System.Reflection.TypeAttributes.BeforeFieldInit type attribute. This limits runtime optimization. A field declared as static readonly may only be assigned as part of its declaration or in a static constructor. When an explicit static constructor isn't required, initialize static fields at declaration rather than through a static constructor for better runtime optimization. The runtime calls a static constructor no more than once in a single application domain. That call is made in a locked region based on the specific type of the class. No additional locking mechanisms are needed in the body of a static constructor. To avoid the risk of deadlocks, don't block the current thread in static constructors and initializers. For example, don't wait on tasks, threads, wait handles or events, don't acquire locks, and don't execute blocking parallel operations such as parallel loops, Parallel.Invoke and Parallel LINQ queries.
[!请注意) 虽然不能直接访问,但应该记录显式静态构造函数的存在,以帮助排除初始化异常。
使用
静态构造函数的典型用法是类使用日志文件,构造函数用于向该文件写入条目。 当构造函数可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装器类时也很有用。 静态构造函数也是一个方便的地方,可以强制执行在编译时不能通过类型参数约束进行检查的类型参数的运行时检查。
推荐文章
- 在c#中从URI字符串获取文件名
- 检查SqlDataReader对象中的列名
- 如何将类标记为已弃用?
- c# 8支持。net框架吗?
- Linq-to-Entities Join vs GroupJoin
- 为什么字符串类型的默认值是null而不是空字符串?
- 在list中获取不同值的列表
- 组合框:向项目添加文本和值(无绑定源)
- 如何为ASP.net/C#应用程序配置文件值中的值添加&号
- 从System.Drawing.Bitmap中加载WPF BitmapImage
- 如何找出一个文件存在于c# / .NET?
- 为什么更快地检查字典是否包含键,而不是捕捉异常,以防它不?
- [DataContract]的命名空间
- string. isnullorempty (string) vs. string. isnullowhitespace (string)
- 完全外部连接