我想知道这个类是否是线程安全的
我可以在不执行锁定的情况下访问Currencies
属性的getter吗?
我是否应该锁定Currencies
方法中对GetLiveExchangeRates()
属性的访问权限?
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();
}
}
}
修改
你会如何重构它?
答案 0 :(得分:1)
如果你必须坚持使用静态类,我会像这样重构这个类:
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;
}
}
将方法重命名为更好地描述实际情况的内容。当你称之为GetLiveExchangeRates
时,我希望它能够返回汇率而不是无效。然后我将所有构造函数一起删除并创建一个返回集合的GetCurrencies()
方法,如果集合为null则创建一个空方法。您公开的集合Currencies
似乎不应作为List公开公开,因为消费者可以更改它。你没有解释集合的重点是什么,所以我试图通过你的命名约定推断出发生了什么。
如果我写这篇文章,我可能会将其隐藏在服务之后。无需静态类。您在视图模型/控制器/服务中拥有对您所拥有的汇率的参考。当您需要刷新它们时,再次点击该服务。
public class CurrencyService
{
public IEnumerable<CurrencyModel> GetLiveExchangeRates()
{
return GetSomeFooLiveDataFromInternet();
}
}
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;
}
}
这或多或少是一项实施变更。您的控制器/ viewmodel将继续点击GetLiveExchangeRates()
,但它只会从您的外部服务获取一次。之后每次都会返回缓存。您只需支付一次锁定费用,然后当其他物品同时到达您的服务时,您不再支付锁定费用。