我有一个ASP.NET MVC应用程序。我的应用程序在视图中使用剃须刀。我的视图有一个复选框列表。呈现的HTML如下所示:
<ul>
<li>
<input type="checkbox" name="SelectedValues" value="1" id="1" />
<label for="1">Option 1</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="2" id="2" />
<label for="2">Option 2</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="3" id="3" />
<label for="3">Option 3</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="4" id="4" />
<label for="4">Option 4</label>
</li>
</ul>
当用户点击&#34;保存&#34;时,这些值会以int[] SelectedValues
的形式存储在我的模型中。
我的挑战是,我的数据库只有一个int类型的字段。我可以在SelectedValues
上进行某种按位XOR并且安全吗?如果是这样,我将如何在C#中的SelectedValues
上执行此操作?
谢谢!
答案 0 :(得分:3)
是的,你问的是可能的,唯一的问题是因为你选择了执行或会导致冲突的价值观。
例如:1 | 2 == 3
代码如何选择1,2
或仅3
。
解决方案是将其转换为位。您可以使用<<
表示法执行此操作。 <<
会将值向左移位一些位。
1<<0
为您提供1
或00000001
作为8位二进制文件1<<1
为您提供1
或00000010
作为8位二进制文件1<<2
为您提供1
或00000100
作为8位二进制文件1<<3
为您提供1
或00001000
作为8位二进制文件1<<4
为您提供1
或00010000
作为8位二进制文件正如您所看到的,每个项目都有一个唯一的字节数组,因此您可以将它们或它们组合在一起以提供组合结果
1<<0 | 1<<2
以8位二进制文件为您提供5
或00000101
这完全可以解决。
(5 & 1<<2) != 0
会告诉您是否设置了第2位。要实现,您可以使用Linq转换数组。
从你的整数数组中获取一个整数:
var array = new[] {1,2,4};
var result = array.Aggregate(0, (x,y) => x | 1<<(y-1));
我从每个值中取出1,因此1的int值变为1
要反转此操作,您可以再次使用linq创建数组。
var value = 5;
var result = Enumerable.Range(1,8).Select(x => (value & 1<<(x-1)) !=0).ToArray();
这将返回一个bool数组,指示每个位的真或假。
只获取设定值列表:
var value = 5;
var result = Enumerable.Range(1,8).Where(x => (value & 1<<(x-1))!=0).Select(x => 1 << (x-1)).ToArray();
此功能适用于8个值,但会将其更改为适合。
请记住,您可以存储在一个整数中的最大位数,检查其16位整数的大小,其他为32位。 c#作为一种语言有32位整数,更长时间使用。
此外,您不应该使用最高位,因为有符号整数使用最高位进行签名。
答案 1 :(得分:1)
首先,你的值是错误的,你需要使用与被设置的位相关的标志,1
,2
,4
,8
,{{ 1}} ...等
16
所以
1 == 0001
2 == 0010
4 == 0100
8 == 1000
etc.
然后你只需加上你的int
<ul>
<li>
<input type="checkbox" name="SelectedValues" value="1" id="1" />
<label for="1">Option 1</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="2" id="2" />
<label for="2">Option 2</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="4" id="3" />
<label for="3">Option 3</label>
</li>
<li>
<input type="checkbox" name="SelectedValues" value="8" id="4" />
<label for="4">Option 4</label>
</li>
</ul>
或使用linq:
int bitFlag = 0;
if (Model.SelectedValues !=null)
{
foreach(int value in Model.SelectedValues)
bitFlag += value;
}
因此,int bitFlag = 0;
if (Model.SelectedValues !=null)
bitFlag = Model.SelectedValues.Sum(s => s);
和1
被检查为4
或0101
为整数
答案 2 :(得分:1)
对于我的罪过,我做过这个练习。我已将数据存储在C#Flag Enum中(这是一种以按位方式存储枚举的方式)并显示在UI中。
在您的示例中,枚举类似于
[Flags]
public enum SelectedValues
{
[Display("Option 1")]
Option1= 1,
[Display("Option 2")]
Option2= 2,
[Display("Option 3")]
Option3= 4,
[Display("Option 4")]
Option4= 8
}
在您的示例中,您的视图模型必须具有SelectedValues类型的成员。
然后我使用显示模板设置一组复选框。我是通过为Flag Enums
创建HTML帮助程序来实现的public static class FlagEnumHelpers
{
public static IHtmlString CheckBoxForFlagEnum<T>(this HtmlHelper<T> html, Enum item)
{
TemplateInfo templateInfo = html.ViewData.TemplateInfo;
string id = templateInfo.GetFullHtmlFieldId(item.ToString());
string name = templateInfo.GetFullHtmlFieldId(string.Empty);
var checkbox = new TagBuilder("input");
checkbox.Attributes["id"] = id;
checkbox.Attributes["name"] = name;
checkbox.Attributes["type"] = "checkbox";
checkbox.Attributes["value"] = item.ToString();
var model = html.ViewData.Model as Enum;
if (model != null && model.HasFlag(item))
{
checkbox.Attributes["checked"] = "checked";
}
return MvcHtmlString.Create(checkbox.ToString());
}
}
然后创建了一个编辑模板(在Views / Shared / EditorTemplates中),在你的情况下称为SelectedValues.cshtml,看起来像
@model Your.Namespace.SelectedValues?
<ul>
<li>
@Html.CheckBoxForFlagEnum(SelectedValues.Option1)
</li>
<li>
@Html.CheckBoxForFlagEnum(SelectedValues.Option2)
</li>
<li>
@Html.CheckBoxForFlagEnum(SelectedValues.Option3)
</li>
<li>
@Html.CheckBoxForFlagEnum(SelectedValues.Option4)
</li>
</ul>
老实说虽然我对它不满意。我认为MVC和Enums /按位操作不能很好地相互配合。
答案 3 :(得分:-1)
另存为Option 1 | Option 2 | Option 3 | Option 4
但为此目的,您的值必须为1 2 4 8 16 32 ...
,依此类推