[英]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.