Dictionary.ContainsKey() 在 C# 中找不到字典中的键
Dictionary.ContainsKey() in C# is not finding a key in the Dictionary
我正在尝试为 privileges/permissions 写 class。
我正在尝试使用 C# 中的二进制基本权限系统。
我在我认为它应该起作用的地方得到了它。但是,它没有按预期工作。
之后,我逐步查看了我的代码,我可以在名为 _mapPermissions
的方法中看到一个问题,该行 if (dic.ContainsKey(vv))
returns false every time.
键是 class 的一个实例,它有 2 个值(即 secionName
、KeyIndex
)
这是我的全部class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MySql.Data.MySqlClient;
namespace POS
{
class Roles
{
private Dictionary<PermissionsKey, int> systemPermissions = new Dictionary<PermissionsKey, int>();
private Dictionary<PermissionsKey, int> userPermissions = new Dictionary<PermissionsKey, int>();
public Roles()
{
this._getSystemPrivleges();
this._getUserPrivleges();
this._display(systemPermissions);
this._display(userPermissions);
}
public bool hasAccess(string sectionName, string[] keys)
{
if ( this.systemPermissions.Count == 0
|| this.userPermissions.Count == 0
|| keys.Count() == 0
|| String.IsNullOrEmpty(sectionName)
)
{
return false;
}
int systemReq = this._mapPermissions(sectionName, keys, systemPermissions); ;
int userPerm = this._mapPermissions(sectionName, keys, userPermissions);
int check = systemReq & userPerm;
Common.Alert("System Value" + systemReq + Environment.NewLine +"User Value " + userPerm + Environment.NewLine + "AND Results " + check);
if (check == 0)
{
return false;
}
return true;
}
private int _mapPermissions(string secName, string[] keys, Dictionary<PermissionsKey, int> dic)
{
int newKey = 0;
var vv = new PermissionsKey();
foreach (string k in keys)
{
vv.sectionName = secName;
vv.KeyIndex = k;
if (dic.ContainsKey(vv))
{
newKey |= dic[vv] ;
}
}
return newKey;
}
private void _getSystemPrivleges()
{
var db = new dbConnetion();
string sql = " SELECT SQL_CACHE "
+ " KeyIndex, Value, sectionName "
+ " FROM role_keys "
+ " WHERE status = 'active' ";
foreach (var i in db.getData(sql, null, r => new SystemPermissions()
{
pIndex = r["KeyIndex"].ToString()
, pSec = r["sectionName"].ToString()
, pValue = r["Value"].ToString()
}
)
)
{
var vv = new PermissionsKey();
vv.sectionName = i.pSec;
vv.KeyIndex = i.pIndex;
systemPermissions.Add(vv, Convert.ToInt32(i.pValue));
}
}
private void _getUserPrivleges()
{
var db = new dbConnetion();
string sql = " SELECT SQL_CACHE k.sectionName, k.KeyIndex, k.value "
+" FROM users AS su "
+" INNER JOIN role_relation AS r ON r.roleID = su.roleID "
+" INNER JOIN role_keys AS k ON k.KeyID = r.KeyID "
+" WHERE su.status = 'active' AND su.userID = @userid ";
var parms = new List<MySqlParameter>();
parms.Add(new MySqlParameter("@userid", UserInfo.UserID));
foreach (var i in db.getData(sql, parms , r => new SystemPermissions()
{
pIndex = r["KeyIndex"].ToString()
, pSec = r["sectionName"].ToString()
, pValue = r["Value"].ToString()
}
)
)
{
var vv = new PermissionsKey();
vv.sectionName = i.pSec;
vv.KeyIndex = i.pIndex;
userPermissions.Add(vv, Convert.ToInt32(i.pValue));
}
}
private void _display(Dictionary<PermissionsKey, int> dic)
{
string str = "";
foreach (KeyValuePair<PermissionsKey, int> d in dic)
{
var vv = new PermissionsKey();
var c = d.Key;
str += c.sectionName + "_" + c.KeyIndex + " => " + d.Value.ToString() + Environment.NewLine;
}
Common.Alert(str);
}
private int _BinToInt(string str)
{
Regex binary = new Regex("^[01]{1,32}$", RegexOptions.Compiled);
int val = -1;
if (binary.IsMatch(str))
{
val = Convert.ToInt32(str, 2);
}
return val;
}
private string _IntToBin(int number)
{
return Convert.ToString(number, 2);
}
}
class SystemPermissions{
public string pIndex;
public string pSec;
public string pValue;
}
class PermissionsKey
{
public string sectionName;
public string KeyIndex;
}
}
我也是这样用的class
var role = new Roles();
string[] aa = { "view", "use" };
if (role.hasAccess("system", aa))
{
Common.Alert("Welcome");
}
else
{
Common.Alert("NOP!");
}
请注意,方法 Common.Alert()
它只是显示一条消息(即 MessageBox
)
以上代码运行时显示如下
1) systemPermissions
字典的内容按顺序PermissionsKey.sectionName
_PermissionsKey.KeyIndex
=> 值(ie. 1 , 2, 4, 8, 16, 32, 64 .....)
system_do = > 1
system_use => 2
system_view => 4
test_use => 1
test_view => 2
2) usePermissions
字典的内容
system_do = > 1
test_use => 1
问题是 2 个变量 systemReq
和 userPerm
return 每次都是 0。我不确定为什么
int systemReq = this._mapPermissions(sectionName, keys, systemPermissions); ;
int userPerm = this._mapPermissions(sectionName, keys, userPermissions);
为了将某物用作字典键并期望它符合您对什么被认为是相等的期望,您实际上需要定义什么被认为是相同的。
在您的 PermissionsKey
class 中,您没有覆盖 Equals
,这意味着默认的 Equals 方法仍在使用(它是对象引用,并且对于每个特定对象)。
要修复,您需要实际告诉字典如何评估相等性。任何时候你覆盖 Equals
,你也应该 also override GetHashCode
:
class PermissionsKey
{
private string sectionName;
private string keyIndex;
public string SectionName { get { return sectionName; } }
public string KeyIndex { get { return keyIndex; } }
public PermissionsKey(string sectionName, string keyIndex)
{
this.sectionName = sectionName;
this.keyIndex = keyIndex;
}
public override bool Equals(object obj)
{
var key = obj as PermissionsKey;
if (key == null)
return false;
return sectionName.Equals(key.sectionName) &&
keyIndex.Equals(key.keyIndex);
}
//Credit to Jon Skeet from
// for inspiration for this method
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = hash * 16777619 ^ sectionName.GetHashCode();
hash = hash * 16777619 ^ keyIndex.GetHashCode();
return hash;
}
}
}
您正在覆盖 Equals 以实际定义相等性比较。任何时候你试图比较 2 个对象(特别是在 Dictionary
对象中,但任何其他时候你通过调用 .Equals
来比较),你应该定义你自己的比较。如果你不这样做,那么你只是在使用默认的相等比较,这是一个纯粹的反对比较和 2 个对象,除非从同一个对象创建,否则永远不会相等。
同样,当您覆盖 Equals 时,强烈建议您也覆盖 GetHashCode
。 HashCode定义了对象属于哪个"bucket"。遵循 Equals 实现的良好哈希码将通过仅将具有相同哈希码的对象放入相同的桶中来帮助加快比较。标准建议是 2 个相等的对象将始终具有相同的哈希码,但 2 个不等于的对象也可能具有相同的哈希码。实际上,这是框架检查不平等的一种快速方法。如果你得到 2 个不同的哈希码,框架知道对象不相等,但如果哈希码相同,那么它会检查是否相等。
如果您不能或不想覆盖 Equals 和 GetHashCode,那么您还可以选择在字典的构造函数中定义 IEqualityComparer<T>
,
您只需传递一个实现 IEqualityComparer<T>
的对象,在该对象中您可以定义所需的相等比较。
此外,任何你打算用作字典键的东西都应该永远是可变的,特别是用于计算相等性和计算哈希码的字段,否则你的键可以由于对象的散列码与最初放入字典中的内容不匹配而迷路。我已经修改了您的原始示例,将您在 PermissionsKey 中的字段更改为不可变属性,并添加了一个构造函数以允许您在最初创建时设置它们一次。
我正在尝试为 privileges/permissions 写 class。
我正在尝试使用 C# 中的二进制基本权限系统。
我在我认为它应该起作用的地方得到了它。但是,它没有按预期工作。
之后,我逐步查看了我的代码,我可以在名为 _mapPermissions
的方法中看到一个问题,该行 if (dic.ContainsKey(vv))
returns false every time.
键是 class 的一个实例,它有 2 个值(即 secionName
、KeyIndex
)
这是我的全部class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MySql.Data.MySqlClient;
namespace POS
{
class Roles
{
private Dictionary<PermissionsKey, int> systemPermissions = new Dictionary<PermissionsKey, int>();
private Dictionary<PermissionsKey, int> userPermissions = new Dictionary<PermissionsKey, int>();
public Roles()
{
this._getSystemPrivleges();
this._getUserPrivleges();
this._display(systemPermissions);
this._display(userPermissions);
}
public bool hasAccess(string sectionName, string[] keys)
{
if ( this.systemPermissions.Count == 0
|| this.userPermissions.Count == 0
|| keys.Count() == 0
|| String.IsNullOrEmpty(sectionName)
)
{
return false;
}
int systemReq = this._mapPermissions(sectionName, keys, systemPermissions); ;
int userPerm = this._mapPermissions(sectionName, keys, userPermissions);
int check = systemReq & userPerm;
Common.Alert("System Value" + systemReq + Environment.NewLine +"User Value " + userPerm + Environment.NewLine + "AND Results " + check);
if (check == 0)
{
return false;
}
return true;
}
private int _mapPermissions(string secName, string[] keys, Dictionary<PermissionsKey, int> dic)
{
int newKey = 0;
var vv = new PermissionsKey();
foreach (string k in keys)
{
vv.sectionName = secName;
vv.KeyIndex = k;
if (dic.ContainsKey(vv))
{
newKey |= dic[vv] ;
}
}
return newKey;
}
private void _getSystemPrivleges()
{
var db = new dbConnetion();
string sql = " SELECT SQL_CACHE "
+ " KeyIndex, Value, sectionName "
+ " FROM role_keys "
+ " WHERE status = 'active' ";
foreach (var i in db.getData(sql, null, r => new SystemPermissions()
{
pIndex = r["KeyIndex"].ToString()
, pSec = r["sectionName"].ToString()
, pValue = r["Value"].ToString()
}
)
)
{
var vv = new PermissionsKey();
vv.sectionName = i.pSec;
vv.KeyIndex = i.pIndex;
systemPermissions.Add(vv, Convert.ToInt32(i.pValue));
}
}
private void _getUserPrivleges()
{
var db = new dbConnetion();
string sql = " SELECT SQL_CACHE k.sectionName, k.KeyIndex, k.value "
+" FROM users AS su "
+" INNER JOIN role_relation AS r ON r.roleID = su.roleID "
+" INNER JOIN role_keys AS k ON k.KeyID = r.KeyID "
+" WHERE su.status = 'active' AND su.userID = @userid ";
var parms = new List<MySqlParameter>();
parms.Add(new MySqlParameter("@userid", UserInfo.UserID));
foreach (var i in db.getData(sql, parms , r => new SystemPermissions()
{
pIndex = r["KeyIndex"].ToString()
, pSec = r["sectionName"].ToString()
, pValue = r["Value"].ToString()
}
)
)
{
var vv = new PermissionsKey();
vv.sectionName = i.pSec;
vv.KeyIndex = i.pIndex;
userPermissions.Add(vv, Convert.ToInt32(i.pValue));
}
}
private void _display(Dictionary<PermissionsKey, int> dic)
{
string str = "";
foreach (KeyValuePair<PermissionsKey, int> d in dic)
{
var vv = new PermissionsKey();
var c = d.Key;
str += c.sectionName + "_" + c.KeyIndex + " => " + d.Value.ToString() + Environment.NewLine;
}
Common.Alert(str);
}
private int _BinToInt(string str)
{
Regex binary = new Regex("^[01]{1,32}$", RegexOptions.Compiled);
int val = -1;
if (binary.IsMatch(str))
{
val = Convert.ToInt32(str, 2);
}
return val;
}
private string _IntToBin(int number)
{
return Convert.ToString(number, 2);
}
}
class SystemPermissions{
public string pIndex;
public string pSec;
public string pValue;
}
class PermissionsKey
{
public string sectionName;
public string KeyIndex;
}
}
我也是这样用的class
var role = new Roles();
string[] aa = { "view", "use" };
if (role.hasAccess("system", aa))
{
Common.Alert("Welcome");
}
else
{
Common.Alert("NOP!");
}
请注意,方法 Common.Alert()
它只是显示一条消息(即 MessageBox
)
以上代码运行时显示如下
1) systemPermissions
字典的内容按顺序PermissionsKey.sectionName
_PermissionsKey.KeyIndex
=> 值(ie. 1 , 2, 4, 8, 16, 32, 64 .....)
system_do = > 1
system_use => 2
system_view => 4
test_use => 1
test_view => 2
2) usePermissions
字典的内容
system_do = > 1
test_use => 1
问题是 2 个变量 systemReq
和 userPerm
return 每次都是 0。我不确定为什么
int systemReq = this._mapPermissions(sectionName, keys, systemPermissions); ;
int userPerm = this._mapPermissions(sectionName, keys, userPermissions);
为了将某物用作字典键并期望它符合您对什么被认为是相等的期望,您实际上需要定义什么被认为是相同的。
在您的 PermissionsKey
class 中,您没有覆盖 Equals
,这意味着默认的 Equals 方法仍在使用(它是对象引用,并且对于每个特定对象)。
要修复,您需要实际告诉字典如何评估相等性。任何时候你覆盖 Equals
,你也应该 also override GetHashCode
:
class PermissionsKey
{
private string sectionName;
private string keyIndex;
public string SectionName { get { return sectionName; } }
public string KeyIndex { get { return keyIndex; } }
public PermissionsKey(string sectionName, string keyIndex)
{
this.sectionName = sectionName;
this.keyIndex = keyIndex;
}
public override bool Equals(object obj)
{
var key = obj as PermissionsKey;
if (key == null)
return false;
return sectionName.Equals(key.sectionName) &&
keyIndex.Equals(key.keyIndex);
}
//Credit to Jon Skeet from
// for inspiration for this method
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = hash * 16777619 ^ sectionName.GetHashCode();
hash = hash * 16777619 ^ keyIndex.GetHashCode();
return hash;
}
}
}
您正在覆盖 Equals 以实际定义相等性比较。任何时候你试图比较 2 个对象(特别是在 Dictionary
对象中,但任何其他时候你通过调用 .Equals
来比较),你应该定义你自己的比较。如果你不这样做,那么你只是在使用默认的相等比较,这是一个纯粹的反对比较和 2 个对象,除非从同一个对象创建,否则永远不会相等。
同样,当您覆盖 Equals 时,强烈建议您也覆盖 GetHashCode
。 HashCode定义了对象属于哪个"bucket"。遵循 Equals 实现的良好哈希码将通过仅将具有相同哈希码的对象放入相同的桶中来帮助加快比较。标准建议是 2 个相等的对象将始终具有相同的哈希码,但 2 个不等于的对象也可能具有相同的哈希码。实际上,这是框架检查不平等的一种快速方法。如果你得到 2 个不同的哈希码,框架知道对象不相等,但如果哈希码相同,那么它会检查是否相等。
如果您不能或不想覆盖 Equals 和 GetHashCode,那么您还可以选择在字典的构造函数中定义 IEqualityComparer<T>
,
您只需传递一个实现 IEqualityComparer<T>
的对象,在该对象中您可以定义所需的相等比较。
此外,任何你打算用作字典键的东西都应该永远是可变的,特别是用于计算相等性和计算哈希码的字段,否则你的键可以由于对象的散列码与最初放入字典中的内容不匹配而迷路。我已经修改了您的原始示例,将您在 PermissionsKey 中的字段更改为不可变属性,并添加了一个构造函数以允许您在最初创建时设置它们一次。