Как инициализировать ConcurrentDictionary? Ошибка: не удается получить доступ к частному методу «Добавить» здесь

У меня есть статический класс, в котором я использую словари в качестве таблиц поиска для сопоставления типов .NET и типов SQL. Вот пример такого словаря:

private static readonly Dictionary<Type, string> SqlServerMap = new Dictionary<Type, string>
{
    {typeof (Boolean), "bit"},
    {typeof (Byte[]), "varbinary(max)"},
    {typeof (Double), "float"},
    {typeof (Byte), "tinyint"},
    {typeof (Int16), "smallint"},
    {typeof (Int32), "int"},
    {typeof (Int64), "bigint"},
    {typeof (Decimal), "decimal"},
    {typeof (Single), "real"},
    {typeof (DateTime), "datetime2(7)"},
    {typeof (TimeSpan), "time"},
    {typeof (String), "nvarchar(MAX)"},
    {typeof (Guid), "uniqueidentifier"}
};

Затем у меня есть общедоступный метод ниже, который передает тип .NET и возвращает строковое значение соответствующего типа MS SQL Server, используя этот словарь. Однако, поскольку это используется в качестве таблицы поиска для выполнения запросов к базе данных, я думаю, имеет смысл сделать ее ConcurrentDictionary. Я изменил его на:

private static readonly IDictionary<Type, string> SqlServerMap = new ConcurrentDictionary<Type, string>
{
    {typeof (Boolean), "bit"},
    {typeof (Byte[]), "varbinary(max)"},
    {typeof (Double), "float"},
    {typeof (Byte), "tinyint"},
    {typeof (Int16), "smallint"},
    {typeof (Int32), "int"},
    {typeof (Int64), "bigint"},
    {typeof (Decimal), "decimal"},
    {typeof (Single), "real"},
    {typeof (DateTime), "datetime2(7)"},
    {typeof (TimeSpan), "time"},
    {typeof (String), "nvarchar(MAX)"},
    {typeof (Guid), "uniqueidentifier"}
};

Но теперь он подчеркивает все красным внутри {} (т. е. все пары ключ-значение ConcurrentDictionary), и возникает ошибка:

Не удается получить доступ к частному методу «Добавить» здесь

Я не думаю, что это потому, что я инициализировал его как private static readonly, потому что я только что проверил, создав версию public static, и получил ту же ошибку.


person Drew    schedule 04.08.2015    source источник
comment
Поскольку ваша коллекция не изменится, теперь вы можете использовать НеизменяемыйСловарь. Хотя это также имеет проблемы с инициализацией, есть решения.   -  person zadj    schedule 04.07.2018


Ответы (5)


Инициализатор коллекции, который вы используете для заполнения коллекции, работает только в том случае, если коллекция имеет метод Add с соответствующей подписью и доступностью. ConcurrentDictionary не имеет общедоступного метода Add, поэтому вы не сможете использовать с ним инициализатор коллекции.

Вы можете предоставить некоторые начальные данные, передав IEnumerable<KeyValuePair<TKey, TValue>> в качестве параметра конструктору, или вы можете вызвать TryAdd (или AddOrUpdate, или любой другой метод с Add в имени) в цикле после создания ConcurrentDictionary.

person Servy    schedule 04.08.2015
comment
А, хорошо, я вижу, спасибо. Я бы хотел, чтобы он уже был инициализирован в static ConcurrentDictionary, так как я знаю, что он не изменится, и я просто хочу получить к нему быстрый доступ. Я посмотрю, что я могу сделать, хотя. - person Drew; 04.08.2015
comment
@Drew И вы можете, передав IEnumerable конструктору, а не используя инициализатор коллекции. - person Servy; 04.08.2015
comment
О, я неправильно понял, что вы имели в виду в своем ответе, спасибо! - person Drew; 04.08.2015

Попробуй это

private static readonly IDictionary<Type, string> SqlServerMap =
    new ConcurrentDictionary<Type, string>(
        new Dictionary<Type, string>()
        {
            {typeof(Boolean ), "bit"             },
            {typeof(Byte[]  ), "varbinary(max)"  },
            {typeof(Double  ), "float"           },
            {typeof(Byte    ), "tinyint"         },
            {typeof(Int16   ), "smallint"        },
            {typeof(Int32   ), "int"             },
            {typeof(Int64   ), "bigint"          },
            {typeof(Decimal ), "decimal"         },
            {typeof(Single  ), "real"            },
            {typeof(DateTime), "datetime2(7)"    },
            {typeof(TimeSpan), "time"            },
            {typeof(String  ), "nvarchar(MAX)"   },
            {typeof(Guid    ), "uniqueidentifier"}
        }
    );

Обновлено: если вы используете C#6 (компилятор Roslyn 2.0), вы можете использовать новые инициализаторы словаря.

private static readonly IDictionary<Type, string> SqlServerMap =
    new ConcurrentDictionary<Type, string>
    {
        [typeof(Boolean )] = "bit"             ,
        [typeof(Byte[]  )] = "varbinary(max)"  ,
        [typeof(Double  )] = "float"           ,
        [typeof(Byte    )] = "tinyint"         ,
        [typeof(Int16   )] = "smallint"        ,
        [typeof(Int32   )] = "int"             ,
        [typeof(Int64   )] = "bigint"          ,
        [typeof(Decimal )] = "decimal"         ,
        [typeof(Single  )] = "real"            ,
        [typeof(DateTime)] = "datetime2(7)"    ,
        [typeof(TimeSpan)] = "time"            ,
        [typeof(String  )] = "nvarchar(MAX)"   ,
        [typeof(Guid    )] = "uniqueidentifier"
    };

Пример https://dotnetfiddle.net/9ZgjsR

person Steven C    schedule 30.01.2017

В качестве примера кода для принятого ответа Servy, чтобы инициализировать ConcurrentDictionary при создании экземпляра, вы можете передать конструктору тип, который влияет на IEnumerable (например, List) из KeyValuePair типов:

private static readonly IDictionary<Type, string> SqlServerMap =
    new ConcurrentDictionary<Type, string>(
        new List<KeyValuePair<Type, string>>
        {
            new KeyValuePair<Type, string>(typeof(Boolean), "bit"),
            new KeyValuePair<Type, string>(typeof(Boolean), "bit"),
            new KeyValuePair<Type, string>(typeof(Byte[]), "varbinary(max)"),
            new KeyValuePair<Type, string>(typeof(Double), "float"),
            new KeyValuePair<Type, string>(typeof(Byte), "tinyint"),
            new KeyValuePair<Type, string>(typeof(Int16), "smallint"),
            new KeyValuePair<Type, string>(typeof(Int32), "int"),
            new KeyValuePair<Type, string>(typeof(Int64), "bigint"),
            new KeyValuePair<Type, string>(typeof(Decimal), "decimal"),
            new KeyValuePair<Type, string>(typeof(Single), "real"),
            new KeyValuePair<Type, string>(typeof(DateTime), "datetime2(7)"),
            new KeyValuePair<Type, string>(typeof(TimeSpan), "time"),
            new KeyValuePair<Type, string>(typeof(String), "nvarchar(MAX)"),
            new KeyValuePair<Type, string>(typeof(Guid), "uniqueidentifier")
        });
person Rufus L    schedule 20.03.2017

Поскольку ваша коллекция не изменится, теперь вы можете использовать НеизменяемыйСловарь. Хотя это также имеет проблемы с инициализацией, для этого предлагаются решения вопрос об инициализации:

Простое решение, предоставленное @LukášLánský:

var d = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } }.ToImmutableDictionary();

и более эффективная версия, предоставленная @IanGriffiths,

public struct MyDictionaryBuilder<TKey, TValue> : IEnumerable
{
    private ImmutableDictionary<TKey, TValue>.Builder _builder;

    public MyDictionaryBuilder(int dummy)
    {
        _builder = ImmutableDictionary.CreateBuilder<TKey, TValue>();
    }

    public void Add(TKey key, TValue value) => _builder.Add(key, value);

    public TValue this[TKey key]
    {
        set { _builder[key] = value; }
    }

    public ImmutableDictionary<TKey, TValue> ToImmutable() => _builder.ToImmutable();

    public IEnumerator GetEnumerator()
    {
        // Only implementing IEnumerable because collection initializer
        // syntax is unavailable if you don't.
    throw new NotImplementedException();
    }
}
person zadj    schedule 04.07.2018

Как сказал @Servy в своем ответе, инициализация коллекции работает для типов с методом Add. Но также это должно работать, если существует метод расширения с именем Add и соответствующей подписью. Таким образом, вы можете создать его для параллельного словаря. Инициализация будет потокобезопасной, поскольку вы используете инициализатор статического поля.

person Uladzislau    schedule 04.08.2015