请向我解释一下静态构造函数的用法.我们为什么以及何时创建静态构造函数,是否可以重载一个?
这是C#的详细问题.
假设我有一个带有对象的类,并且该对象受到锁的保护:
Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
get {
return property;
}
set {
property = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我想要一个轮询线程来查询该属性.我还希望线程偶尔更新该对象的属性,有时用户可以更新该属性,并且用户希望能够看到该属性.
以下代码是否会正确锁定数据?
Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
get {
lock (mLock){
return property;
}
}
set {
lock (mLock){
property = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
通过'正确',我的意思是,如果我想打电话
MyProperty.Field1 = 2;
Run Code Online (Sandbox Code Playgroud)
或者其他什么,我会在更新时锁定该字段?设置是由'get'函数范围内的equals运算符完成的,还是'get'函数(因此锁定)首先完成,然后设置,然后'set'被调用,从而绕过锁?
编辑:由于这显然不会做的伎俩,会是什么?我是否需要做以下事情:
Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
get {
MyObject tmp = null;
lock …
Run Code Online (Sandbox Code Playgroud) 我正在C#中构建一个多线程缓存,它将包含一个Car对象列表:
public static IList<Car> Cars {get; private set;}
Run Code Online (Sandbox Code Playgroud)
我想知道在没有锁定的情况下更改线程中的引用是否安全?
例如
private static void Loop()
{
while (true)
{
Cars = GetFreshListFromServer();
Thread.Sleep(SomeInterval);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,它归结为是否为汽车分配新的参考是原子的还是不是我想的.
如果不是,我显然必须为我的汽车使用私人领域,并锁定获取和设置.
因此,使用单例模式的对象只能有一个实例.这在网站上如何运作?
问题:
我一直在使用这种模式来初始化我的类中的静态数据.它看起来对我来说是安全的,但我知道细微的线程问题是多么微妙.这是代码:
public class MyClass // bad code, do not use
{
static string _myResource = "";
static volatile bool _init = false;
public MyClass()
{
if (_init == true) return;
lock (_myResource)
{
if (_init == true) return;
Thread.Sleep(3000); // some operation that takes a long time
_myResource = "Hello World";
_init = true;
}
}
public string MyResource { get { return _myResource; } }
}
Run Code Online (Sandbox Code Playgroud)
这里有洞吗?也许有一种更简单的方法可以做到这一点.
更新:共识似乎是静态构造函数是要走的路.我使用静态构造函数提出了以下版本.
public class MyClass
{
static MyClass() // a static constructor
{ …
Run Code Online (Sandbox Code Playgroud) 假设你有一个像这样的简单类:
class MyClass
{
private readonly int a;
private int b;
public MyClass(int a, int b) { this.a = a; this.b = b; }
public int A { get { return a; } }
public int B { get { return b; } }
}
Run Code Online (Sandbox Code Playgroud)
我可以以多线程方式使用这个类:
MyClass value = null;
Task.Run(() => {
while (true) { value = new MyClass(1, 1); Thread.Sleep(10); }
});
while (true)
{
MyClass result = value;
if (result != null && (result.A != 1 || …
Run Code Online (Sandbox Code Playgroud) 鉴于:
public class MyClass
{
private static readonly Dictionary<string,int> mydict = CreateDictionary();
private static Dictionary<string,int> CreateDictionary() { ... }
}
Run Code Online (Sandbox Code Playgroud)
这是同步完成的吗?(即可以两次快速实例化MyClass
原因CreateDictionary()
被调用两次?
在我们的SharePoint/ASP.NET环境中,我们有一系列数据检索器类,这些类都来自通用接口.我被分配了创建数据检索器的任务,该数据检索器可以使用WCF与其他SharePoint场远程通信.我现在实现它的方式ChannelFactory<T>
是在静态构造函数中创建单例,然后由远程数据检索器的每个实例重用,以创建单独的代理实例.我认为这样可以很好地工作,因为那时ChannelFactory
只在app域中实例化一次并且它的创建保证是线程安全的.我的代码看起来像这样:
public class RemoteDataRetriever : IDataRetriever
{
protected static readonly ChannelFactory<IRemoteDataProvider>
RequestChannelFactory;
protected IRemoteDataProvider _channel;
static RemoteDataRetriever()
{
WSHttpBinding binding = new WSHttpBinding(
SecurityMode.TransportWithMessageCredential, true);
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
RequestChannelFactory =
new ChannelFactory<IRemoteDataProvider>(binding);
}
public RemoteDataRetriever(string endpointAddress)
{
_channel = RemoteDataRetriever.RequestChannelFactory.
CreateChannel(new EndpointAddress(endpointAddress));
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是一个很好的设计吗?我想,一旦ChannelFactory
创建,我不需要担心线程安全,因为我只是用它来打电话,CreateChannel()
但我错了吗?它是在改变状态还是在幕后做一些可能导致线程问题的时髦的东西?另外,我是否需要在某个地方放置一些代码(静态终结器?)来手动处理ChannelFactory
或者我可以假设每当IIS重新启动它时,它会为我做所有的清理工作吗?
wcf singleton static-constructor thread-safety channelfactory
可能重复:
C#静态构造函数线程是否安全?
Jon Skeet在http://csharpindepth.com/Articles/General/Singleton.aspx上的精彩文章以及我读过的其他文章清楚地表明,双重检查锁定在C#和Java中都不起作用,除非有明确标记实例为"易变".如果不这样做,则将其与null进行比较的检查可能会返回false,即使实例构造函数尚未完成运行.在Skeet先生的第三个样本中,他清楚地说明了这一点:"Java内存模型不能确保构造函数在将新对象的引用分配给实例之前完成.Java内存模型经历了1.5版的重新修改,但是在没有volatile变量的情况下,-check锁定仍然被破坏(如在C#中)
但是,大多数人都同意(包括Skeet先生,他的文章中的第4和第5个样本),使用静态初始化是获取线程安全单例实例的简单方法.他声称"C#中的静态构造函数被指定仅在创建类的实例或引用静态成员时执行,并且每个AppDomain只执行一次."
这是有道理的,但似乎缺少的是保证仅在构造函数完成后才分配对新对象的引用 - 否则我们会遇到使得双重检查锁定失败的同类问题,除非您标记实例像挥发性的.是否有保证,当使用静态初始化来调用实例构造函数(而不是从属性的get {}调用实例构造函数时,就像我们使用双重检查锁定一样),构造函数将在任何其他线程之前完全完成可以获得对象的引用?
谢谢!
public class MyClass<T>
{
public static readonly String MyStringValue;
static MyClass()
{
MyStringValue = GenerateString();
}
private static String GenerateString()
{
//Dynamically generated ONCE per type (hence, not const)
}
public void Foo()
{
Console.WriteLine(MyStringValue);
}
}
Run Code Online (Sandbox Code Playgroud)
我的理解是,在类上调用静态构造函数之前,不会生成静态readonly String.但是,在访问其中一个静态方法或变量之前,不会调用静态构造函数.
在多线程环境中,是否可能因此而遇到问题?基本上,静态构造函数是默认单例锁定还是我自己必须这样做?那是......我必须做以下事情:
private static Object MyLock;
static MyClass()
{
lock(MyLock)
{
if (MyStringValue == null)
MyStringValue = GenerateString();
}
}
Run Code Online (Sandbox Code Playgroud) 我相信第一个代码示例是一个简单的Singleton实现,我不确定它是否是线程安全的.作为类,EventSourceLogger派生自EventSource,它不是静态的,这个类本身不能只是一个静态类(这本来更方便 - 尽管在单一和静态之间进行权衡).
为了简洁起见,我从一个更彻底的特定已知线程安全实现恢复到此实现 - 在同事代码中喜欢这种方法的外观之后.我丢了什么?
目前的实施
[EventSource(Name = "EventSourceLogger")]
public class EventSourceLogger : EventSource
{
public static readonly EventSourceLogger Logger = new EventSourceLogger();`
}
Run Code Online (Sandbox Code Playgroud)
以前的实施
[EventSource(Name = "EventSourceLogger")]
public class EventSourceLogger : EventSource
{
private static EventSourceLogger instance;
private EventSourceLogger()
{
}
public static EventSourceLogger Instance
{
get
{
if (instance == null)
{
instance = new EventSourceLogger();
}
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud) 所以我有一个类A。它定义了很多行为(方法),但也留下了很多子类来实现。这个类永远不会有实例。这只是定义所有子类共有的行为。将扩展 A 的子类(A1、A2、A3 等)都将是单例。我不希望这些子类有多个实例。
因此,最明显的方法是创建一个抽象类 A,然后创建扩展 A 的静态类 A1、A2、A3。
但显然,这在 C# 中是不允许的。我认为这是有充分理由的。微软的人可能比我更了解面向对象的软件设计。但我只需要一些帮助来弄清楚为什么这个设计“很差”,以及什么是替代的更好的设计。
我正在使用 WCF 编写 RESTful API。该服务将在一堆数据库表上执行 CRUD 操作。有很多代码对于所有表来说都是通用的,并且很多代码对于每个表来说都是特定的。此外,在任何给定时间只能对表执行一项操作。
所以我想我可以有一个抽象类TableHandler
。然后是它的多个扩展,例如等TableAHandler
。TableBHandler
由于我只想要这些子类的一个实例,所以我想将它们设为静态。
按照单身模式,
public sealed class Singleton
{
static Singleton instance=null;
Singleton()
{
}
public void abc(){
}
public static Singleton Instance
{
get
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud)
以上不是线程安全的.两个不同的线程都可以评估测试if(instance == null)并发现它是真的,然后两个都创建实例,这违反了单例模式.
混淆是实例是静态的,一旦在UI线程或其他线程上调用它,它是如何为null的?
编辑
我打算说,一旦我调用了Singleton.Instance.abc(); Singleton.Instance在手动处理之前不应为null.对?
c# ×12
singleton ×6
static ×3
constructor ×2
asp.net ×1
inheritance ×1
locking ×1
memory-model ×1
oop ×1
properties ×1
readonly ×1
synchronous ×1
volatile ×1
wcf ×1