我担心使用枚举作为键的通用字典。
如下页所述,对键使用枚举将分配内存: http://blogs.msdn.com/b/shawnhar/archive/2007/07/02/twin-paths-to-garbage-collector-nirvana.aspx
我已经测试并确认了该行为,它在我的项目中引起了问题。为了可读性,我相信对键使用枚举非常有用,对我来说最佳解决方案是编写一个实现 IDictionary<TKey, TValue> 的类。 ,这将在内部使用整数作为键。原因是我不想更改所有现有词典以使用整数作为键,并进行隐式转换。这将是最好的性能明智的做法,但它会在一开始给我做很多工作,并且会降低可读性。
所以我尝试了几种方法,包括使用 GetHashCode (不幸的是分配内存)来构建一个内部 Dictionary<int, TValue> .
因此,将其总结为一个问题;谁能想到一个解决方案,我可以用它来保持 Dictionary<SomeEnum, TValue> 的可读性,同时具有 Dictionary<int, TValue> 的性能?
非常感谢任何建议。
最佳答案
问题是装箱。这是将值类型转换为对象的行为,这可能是不必要的,也可能不是。
方式Dictionary比较键,本质上是,它将使用 EqualComparer<T>.Default , 并调用 GetHashCode()找到正确的桶,Equals比较桶中是否有任何值等于我们正在寻找的值。
好处是:.NET Framework 有很好的优化,在 "Enum integers" 的情况下避免装箱.参见 CreateComparer() .作为键,您不太可能在这里看到整数和枚举之间的任何差异。
这里要注意:这不是一件容易的事,事实上,如果你深入挖掘,你会得出结论,这场战斗的四分之一是通过 CLR“黑客”实现的。如此处所示:
static internal int UnsafeEnumCast<T>(T val) where T : struct
{
// should be return (int) val; but C# does not allow, runtime
// does this magically
// See getILIntrinsicImplementation for how this happens.
throw new InvalidOperationException();
}
如果泛型有 Enum 约束,那肯定会更容易,甚至可能是很长的行 UnsafeEnumCast<T>(T val) where T : Enum->Integer ,但是……他们没有。
您可能想知道,getILIntrinsicImplementation 中到底发生了什么 EnumCast ?我也想知道。目前还不确定如何检查它。我相信它在运行时被替换为特定的 IL 代码?!
现在,回答您的问题:是的,您是对的。 Enum作为 Mono 上的键,在紧密循环中会变慢。据我所知,这是因为 Mono 在枚举上进行装箱。你可以看看EnumIntEqualityComparer ,如您所见,它调用了 Array.UnsafeMov这基本上是一种类型 T成整数,通过装箱:(int)(object) instance; .这是泛型的“经典”局限性,并且没有很好的解决方案。
实现 EqualityComparer<MyEnum>为您的具体枚举。这将避免所有转换。
public struct MyEnumCOmparer : IEqualityComparer<MyEnum>
{
public bool Equals(MyEnum x, MyEnum y)
{
return x == y;
}
public int GetHashCode(MyEnum obj)
{
// you need to do some thinking here,
return (int)obj;
}
}
然后您需要做的就是将其传递给您的 Dictionary :
new Dictionary<MyEnum, int>(new MyEnumComparer());
它有效,它为您提供与整数相同的性能,并避免了装箱问题。问题是,这不是通用的,并且为每个 Enum 写这个会觉得很傻。
编写一个通用的 Enum比较器,并使用一些避免拆箱的技巧。我在 here 的帮助下写了这篇文章,
// todo; check if your TEnum is enum && typeCode == TypeCode.Int
struct FastEnumIntEqualityComparer<TEnum> : IEqualityComparer<TEnum>
where TEnum : struct
{
static class BoxAvoidance
{
static readonly Func<TEnum, int> _wrapper;
public static int ToInt(TEnum enu)
{
return _wrapper(enu);
}
static BoxAvoidance()
{
var p = Expression.Parameter(typeof(TEnum), null);
var c = Expression.ConvertChecked(p, typeof(int));
_wrapper = Expression.Lambda<Func<TEnum, int>>(c, p).Compile();
}
}
public bool Equals(TEnum firstEnum, TEnum secondEnum)
{
return BoxAvoidance.ToInt(firstEnum) ==
BoxAvoidance.ToInt(secondEnum);
}
public int GetHashCode(TEnum firstEnum)
{
return BoxAvoidance.ToInt(firstEnum);
}
}
现在,解决方案#2 有一个小问题,如 Expression.Compile()在 iOS 上不是那么出名(没有运行时代码生成),一些单声道版本没有 ?? Expression.Compile ?? (不确定)。
您可以编写简单的 IL 代码来处理枚举转换并编译它。
.assembly extern mscorlib
{
.ver 0:0:0:0
}
.assembly 'enum2int'
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.class public auto ansi beforefieldinit EnumInt32ToInt
extends [mscorlib]System.Object
{
.method public hidebysig static int32 Convert<valuetype
.ctor ([mscorlib]System.ValueType) TEnum>(!!TEnum 'value') cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_000b: ret
}
}
为了将其编译成程序集,您必须调用:
ilasm enum2int.il /dll其中 enum2int.il 是包含 IL 的文本文件。
您现在可以引用给定的程序集(enum2int.dll)并调用静态方法,如下所示:
struct FastEnumIntEqualityComparer<TEnum> : IEqualityComparer<TEnum>
where TEnum : struct
{
int ToInt(TEnum en)
{
return EnumInt32ToInt.Convert(en);
}
public bool Equals(TEnum firstEnum, TEnum secondEnum)
{
return ToInt(firstEnum) == ToInt(secondEnum);
}
public int GetHashCode(TEnum firstEnum)
{
return ToInt(firstEnum);
}
}
它可能看起来是 killer 级代码,但它避免了装箱,并且它应该在 Mono 上为您提供更好的性能。 .
关于c# - 字典枚举关键性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26280788/
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
我正在尝试学习Ruby词法分析器和解析器(whitequarkparser)以了解更多有关从Ruby脚本进一步生成机器代码的过程。在解析以下Ruby代码字符串时。defadd(a,b)returna+bendputsadd1,2它导致以下S表达式符号。s(:begin,s(:def,:add,s(:args,s(:arg,:a),s(:arg,:b)),s(:return,s(:send,s(:lvar,:a),:+,s(:lvar,:b)))),s(:send,nil,:puts,s(:send,nil,:add,s(:int,1),s(:int,3))))任何人都可以向我解释生成的
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum
如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:
以下是我认为的一些下拉列表:'form-control')%>和'form-control')%>这是我的application_helper.rbdefget_advance_bookingret=[{:require_booking=>'No'},{:require_booking=>'Yes'}]enddefget_instant_bookingret=[{:instant_booking=>'No'},{:instant_booking=>'Yes'}]end但现在的问题是,在我的模型product.rb中,我无法设置具有相同名称的枚举:classProduct我收到的错误是您