加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 使用反射和锁定正确地实例化分配给私有静态volatile变量的

发布时间:2020-12-15 21:25:13 所属栏目:百科 来源:网络整理
导读:所以这是一个我想要改进或确认的人为例子. 我正在使用(我/我)BATIS.NET(一个轻量级的ORM /数据映射器框架),我所拥有的是一个类,它为数据库的每个表映射器提供静态引用.它工作得很好,但有很多重复,我认为可能有机会大大简化代码.该类目前看起来像这样: publi
所以这是一个我想要改进或确认的人为例子.

我正在使用(我/我)BATIS.NET(一个轻量级的ORM /数据映射器框架),我所拥有的是一个类,它为数据库的每个表映射器提供静态引用.它工作得很好,但有很多重复,我认为可能有机会大大简化代码.该类目前看起来像这样:

public sealed class MyRepository
{
    private static string _connectionString;

    private volatile static TableAbcMapper _tableAbcMapper;
    private volatile static TableXyzMapper _tableXyzMapper;
    // and about 30 more of these

    private MyRepository()
    {
    }

    public static void Init(string connectionString)
    {
        _connectionString = connectionString;
    }

    public static string ConnectionString
    {
        get { return _connectionString; }
    }

    public static TableAbcMapper TableAbc
    {
        get
        {
            if (_tableAbcMapper == null)
            {
                lock (typeof(TableAbcMapper))
                {
                    if (_tableAbcMapper == null)
                    {
                        _tableAbcMapper = new TableAbcMapper(_connectionString);
                    }
                }
            }
            return _tableAbcMapper;
        }
    }

    public static TableXyzMapper TableXyz
    {
        get
        {
            if (_tableXyzMapper == null)
            {
                lock (typeof(TableXyzMapper))
                {
                    if (_tableXyzMapper == null)
                    {
                        _tableXyzMapper = new TableXyzMapper(_connectionString);
                    }
                }
            }
            return _tableXyzMapper;
        }
    }

    // and about 30 more of these readonly properties
}

每次我向数据库添加或删除一个表时,我都会向MyRepository类添加一个私有的volatile静态字段和那个丑陋的singleton-y属性.我的第一个想法是让属性在类中调用泛型实例函数;看起来像这样的东西:

private static void InitMapper<TMapper>(TMapper instance) where TMapper : MyMapper
{
    lock (typeof(TMapper))
    {
        if (instance == null)
        {
            instance = Activator.CreateInstance(typeof(TMapper),new object[] { _connectionString }) as TMapper;
        }
    }
}

然后公众的吸气者可以略微减少到:

public static TableXyzMapper TableXyz
{
    get
    {
        if (_tableXyzMapper == null)
        {
            InitMapper<TableXyzMapper>(_tableXyzMapper);
        }
        return _tableXyzMapper;
    }
}

但是,我不知道在volatile字段周围传递是否是一个好主意,并且使用ref或out with volatile字段是禁止的,并且最重要的是它不会减少所有那么多的代码量.

我想要做的是完全重构MyRepository类,使其没有私有字段,也没有公共getter,并使用反射来立即初始化所有映射器而不是延迟加载它们.我不必更改任何使用MyRepository类的代码,因为它看起来完全一样,但是它会有点不同:

public sealed class MyRepository
{
    private MyRepository()
    {
    }

    public volatile static TableAbcMapper TableAbc = null;
    public volatile static TableXyzMapper TableXyz = null;

    public static void Init(string connectionString)
    {
        foreach (var fieldInfo in typeof(MyRepository).GetFields(BindingFlags.Static))
        {
            if (fieldInfo.GetValue(new MyRepository()) == null)
            {
                lock (fieldInfo.FieldType)
                {
                    if (fieldInfo.GetValue(new MyRepository()) == null)
                    {
                        fieldInfo.SetValue(new MyRepository(),fieldInfo.FieldType.GetConstructor(new Type[] { typeof(string) })
                                .Invoke(new object[] { connectionString }));
                    }
                }
            }
        }
    }
}

现在,当新表添加到数据库时,我必须做的唯一维护就是为它添加一个新的公共易失性静态字段,反射将处理其余部分.

我对这种方法有几个问题:

>这种方法在功能上与原始类相同吗?
>使用反射定义volatile变量是否有任何危险?
>它是否与原始类一样可读(假设它已全部注释)?

最后,如果这是一个更适合Code Review网站的问题,我就是为了让它迁移(mods!).

解决方法

它可能不会短得多,但由于你已经有了一个init方法,你可以创建一个在第一次访问时创建的惰性值.关于Lazy(.NET 4的一部分)的好处是你可以指定值可以创建多次,但是它的值只发布一次(给出更好的性能).

class Program
    {
        static Lazy<string> _Lazy;
        static string _connectionString;

        public string LazyValue
        {
            get
            {
                return _Lazy.Value;
            }

        }

        public static void Init(string connectionString)
        {
            _connectionString = connectionString;
            _Lazy = new Lazy<string>(() => new string(connectionString.ToArray()),System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
        }

但它不会变短.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读