Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 静态getter应该是线程安全的吗_C#_Design Patterns - Fatal编程技术网

C# 静态getter应该是线程安全的吗

C# 静态getter应该是线程安全的吗,c#,design-patterns,C#,Design Patterns,我想知道这个类是否是线程安全的 我可以访问货币属性的getter而不执行锁定吗 我是否应该在GetLiveExchangeRates()方法中锁定对Currences属性的访问 public class CurrencyManager { public static List<CurrencyModel> Currencies { get; private set; } private static readonly object LockObj = new obje

我想知道这个类是否是线程安全的

我可以访问
货币
属性的getter而不执行锁定吗

我是否应该在
GetLiveExchangeRates()
方法中锁定对
Currences
属性的访问

public class CurrencyManager
{
    public static List<CurrencyModel> Currencies { get; private set; }
    private static readonly object LockObj = new object();

    public CurrencyManager()
    {
        Currencies = new List<CurrencyModel>();
    }

    public static void GetLiveExchangeRates()
    {
        lock (LockObj)
        {
            Currencies = GetSomeFooLiveDataFromInternet();
        }
    }
}
公共类CurrencyManager
{
公共静态列表货币{get;private set;}
私有静态只读对象LockObj=新对象();
公共货币经理()
{
货币=新列表();
}
公共静态void GetLiveExchangeRates()
{
锁(LockObj)
{
货币=从Internet()获取一些愚蠢的数据;
}
}
}
编辑


您将如何重构它?

如果您必须坚持使用静态类,我将如下重构该类:

public class CurrencyManager
{
    private static readonly IEnumerable<CurrencyModel> currencies = Enumerable<CurrencyModel.Empty();
    private static readonly object LockObj = new object();

    public static void RefreshLiveExchangeRates()
    {
        lock (LockObj)
        {
            CurrencyManager.currencies = GetSomeFooLiveDataFromInternet();
        }
    }

    public static IEnumerable<CurrencyModel> GetCurrencies()
    {
        return CurrencyManager.currencies;
    }
}
消费者(视图模型/控制器等)
公共类MyController
{
私人可数流动利率;
公共MyController()
{
//实例一个新服务;或者通过构造函数作为依赖项提供它
var currencyService=new currencyService();
this.currentRates=currencyService.GetLiveExchangeRates();
}
}
然后,您的消费类将使用它从服务获取的集合。如果它愿意,它可以将该集合传递给依赖它的其他对象。当您觉得集合过时时,可以从服务中重新获取它们。此时,您可能不需要执行任何锁定,因为只有使用者可以使用该属性,并且可以控制何时可以更改该属性。这允许多个实例查询最新的汇率,而不必进行锁定,并让每个人排队接收汇率

理想情况下,我希望看到它作为依赖项通过构造函数传入,隐藏在接口后面,在需要时刷新速率。因此,我不会在构造函数中获取速率,而是在需要时懒洋洋地获取它们。这将允许您异步完成工作(假设您的实际实现是异步的)

编辑 如果出于缓存目的将集合存储在静态类中,则可以将集合存储在服务中,并始终返回集合。只有在清除缓存时,才会返回一组新的汇率

public class CurrencyService
{
    private static IEnumerable<CurrencyModel> currencyRates;
    private static object ratesLock = new object();
    public IEnumerable<CurrencyModel> GetLiveExchangeRates()
    {
        if (currencyRates == null)
        {
            lock (ratesLock)
            {
                currencyRates = GetSomeFooLiveDataFromInternet();
            }
        }

        return currencyRates;
    }

    public void ClearRates()
    {
        currencyRates = null;
    }
}
公共类货币服务
{
私有静态可数货币汇率;
私有静态对象ratesLock=新对象();
公共IEnumerable GetLiveExchangeRates()
{
if(currencyRates==null)
{
锁(速率锁)
{
currencyRates=从Internet()获取一些愚蠢的数据;
}
}
回报率;
}
公共收费
{
currencyRates=null;
}
}

这或多或少是一个实现变更。您的controller/viewmodel将继续点击
GetLiveExchangeRates()
,但它只会从您的外部服务获取一次。每次之后,它都会返回缓存。您只需支付一次锁定费,然后当其他对象同时访问您的服务时,您不再支付锁定费。

尝试使用单例模式。这是错误代码。由于这个bug,线程不安全。当另一个线程创建一个新实例时,不会发生什么好事。好吧,假设没有人创建一个新实例?@dotctor Singleton如何帮助线程安全?实例构造函数为什么更改静态成员?
public class MyController
{
    private IEnumerable<CurrencyModel> currentRates;

    public MyController()
    {
        // Instance a new service; or provide it through the constructor as a dependency
        var currencyService = new CurrencyService();
        this.currentRates = currencyService.GetLiveExchangeRates();
    }
}
public class CurrencyService
{
    private static IEnumerable<CurrencyModel> currencyRates;
    private static object ratesLock = new object();
    public IEnumerable<CurrencyModel> GetLiveExchangeRates()
    {
        if (currencyRates == null)
        {
            lock (ratesLock)
            {
                currencyRates = GetSomeFooLiveDataFromInternet();
            }
        }

        return currencyRates;
    }

    public void ClearRates()
    {
        currencyRates = null;
    }
}