问题
I'm trying to create one object that will be responsible for reading all users access settings.
I've created class as so:
public class SettingsManager
{
private static string _connString =
@"Data Source=MyDB;Initial Catalog=IT;Integrated Security=True;Asynchronous Processing=true;";
private const string _spName = "SettingTest";
private IEnumerable<string> _mySettings;
private static readonly Lazy<SettingsManager> _instance = new Lazy<SettingsManager>(() => new SettingsManager());
private SettingsManager()
{
//Console.WriteLine("Hello from constructor");
if (_mySettings == null)
_mySettings = ReadSettings();
}
public static SettingsManager Instance
{
get { return _instance.Value; }
}
public bool CanDo(string setting)
{
return _mySettings.Contains(setting);
}
private IEnumerable<string> ReadSettings()
{
try
{
using (var conn = new SqlConnection(_connString))
{
using (var cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = _spName;
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
using (var reader = cmd.ExecuteReader())
{
return reader.Select(SettingParser).ToList();
}
}
}
}
catch
{
}
return null;
}
private string SettingParser(SqlDataReader r)
{
try
{
return r[0] is DBNull ? null : r[0].ToString();
}
catch
{
}
return null;
}
}
And SqlDataReader Extension
public static class DBExtensions
{
public static IEnumerable<T> Select<T>(
this SqlDataReader reader, Func<SqlDataReader, T> projection)
{
while (reader.Read())
{
yield return projection(reader);
}
}
}
Then inside my application I'm able to call it as so:
SettingsManager.Instance.CanDo("canWrite")
this returns true/false value depends on user access level.
My questions are:
Is this thread safe? Are there any chances DB will be query multiple times? How to prevent this?
Should I use await and async? I query db just once. How can I improve this? (await and async are really new to me because I just moved from .NET3.5 to 4.5)
回答1:
1) Is this thread safe?
Yes.
Are there any chances DB will be query multiple times?
No.
2) Should I use await and async?
That will depend on whether you need asynchronous access to your database. If you need that you could use the async ADO.NET API.
回答2:
1)yes this is, thread safe
Thread-safe Singleton: This implementation uses an inner class to make the .NET instantiation fully lazy. Only GetInstance() will trigger the type initializer; so, this version is just as lazy as the classic version. And, it will perform as quckly as any other version.
public sealed class Singleton
{
private Singleton() {}
public static Singleton GetInstance()
{
return NestedSingleton.singleton;
}
class NestedSingleton
{
internal static readonly Singleton singleton = new Singleton();
static NestedSingleton() {}
}
}
2)It's depend if you want asynchronous access to your DB.
回答3:
- Is this thread safe?
Yes. You are using the Lazy<T>
type correctly to ensure thread-safety.
- Should I use await and async?
I would recommend it. Right now, the first time your application code calls SettingsManager.Instance.CanDo("canWrite")
, it will block until the DB responds. It's also possible to have an async
implementation where your consumers could do (await SettingsManager.Instance).CanDo("canWrite")
(or await SettingsManager.CanDoAsync("canWrite")
). This means your consumers do not block while waiting for the DB.
You can use an async
-ready version of Lazy<T>
called AsyncLazy<T>
, originally developed by Stephen Toub and included in my AsyncEx library.
来源:https://stackoverflow.com/questions/14932387/ensure-singleton-call-db-query-only-once