简体   繁体   English

如何初始化ConcurrentDictionary? 错误:“无法在此处访问私有方法'添加'”

[英]How to initialize a ConcurrentDictionary? Error: “Cannot access private method 'Add' here”

I have a static class in which I am using dictionaries as lookup tables to map between .NET types and SQL types. 我有一个静态类,其中使用字典作为查找表,以在.NET类型和SQL类型之间进行映射。 Here is an example of such a dictionary: 这是此类字典的示例:

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"}
};

Then I have a public method below which passes in a .NET type and it returns the string value of the corresponding MS SQL Server type using this dictionary. 然后,我下面有一个公共方法,该方法传入.NET类型,它使用此字典返回相应MS SQL Server类型的字符串值。 However, since this is being used as a lookup table for making database queries, I think it makes sense to make it a ConcurrentDictionary . 但是,由于它被用作进行数据库查询的查找表,因此我认为将其设置为ConcurrentDictionary是有意义的。 I changed it to: 我将其更改为:

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"}
};

But now it underlines everything red within the {} (ie all key value pairs of the ConcurrentDictionary ) and the error is: 但是现在,它在{} (即ConcurrentDictionary所有键值对)中的所有红色下划线,错误是:

Cannot access private method 'Add' here 无法在此处访问私有方法“添加”

I don't think it's because I initialize it as private static readonly , because I just tested by making a public static version and I got the same error. 我不认为这是因为我将其初始化为private static readonly ,因为我只是通过制作一个public static版本进行了测试,但遇到了相同的错误。

Try this 尝试这个

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"}
        }
    );

Updated: if you are using C#6(Roslyn 2.0 Compiler), you can use the new Dictionary Initializers. 更新:如果您使用的是C#6(Roslyn 2.0编译器),则可以使用新的Dictionary Initializers。

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"
    };

Example https://dotnetfiddle.net/9ZgjsR 示例https://dotnetfiddle.net/9ZgjsR

The collection initializer that you're using to populate the collection only works if the collection has an Add method of an appropriate signature and accessibility. 仅当集合具有具有适当签名和可访问性的Add方法时,您用于填充集合的集合初始化程序才起作用。 ConcurrentDictionary doesn't have a public Add method, so you won't be able to use a collection initializer with it. ConcurrentDictionary没有公共的Add方法,因此您将无法使用它的集合初始化器。

You can provide some initial data by passing an IEnumerable<KeyValuePair<TKey, TValue>> as a parameter to the constructor, or you can call TryAdd (or AddOrUpdate , or any of the other methods with Add in the name) in a loop after creating the ConcurrentDictionary . 你可以通过一个提供一些初始数据IEnumerable<KeyValuePair<TKey, TValue>>作为参数传递给构造函数,或者也可以称之为TryAdd (或AddOrUpdate ,或与其他方法Add的名字)在一个循环后,创建ConcurrentDictionary

As a code example to Servy's accepted answer, in order to initialize a ConcurrentDictionary at instantiation, you can pass a type that impements IEnumerable (like a List ) of KeyValuePair types to the constructor: 作为Servy接受的答案的代码示例,为了在实例化时初始化ConcurrentDictionary ,您可以将对KeyValuePair类型的IEnumerable (例如List )产生影响的类型传递给构造函数:

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")
        });

As your collection is not going to change, you could now use the ImmutableDictionary . 由于您的收藏集不会更改,因此现在可以使用ImmutableDictionary While this also has issues with the initialize, there are solutions proposed for this question about initialization : 尽管这也存在初始化问题,但针对该初始化问题提出了一些解决方案:

A simple solution provided by @LukášLánský is @LukášLánský提供的一个简单解决方案是

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

and a better performing version provided by @IanGriffiths is @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();
    }
}

As said @Servy in his answer, collection initialization works for types with Add method. 正如@Servy在他的回答中所说,集合初始化适用于使用Add方法的类型。 But also it should work, if extension method with name Add and appropriate signature exists. 但是,如果存在名称为Add且具有适当签名的扩展方法,它也应该起作用。 So you could create one for concurrent dictionary. 因此,您可以为并发字典创建一个。 Initialization will be thread-safe, due to fact you are using static field initializer. 由于您正在使用静态字段初始化程序,因此初始化将是线程安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM