在这里讨论了SO之后,我已经多次读过可变结构是"邪恶"的评论(就像这个问题的答案一样).
C#中可变性和结构的实际问题是什么?
警告:这个问题有点异端......宗教程序员总是遵守良好做法,请不要阅读.:)
有谁知道为什么不鼓励使用TypedReference(隐含地,缺乏文档)?
我已经找到了很好的用途,例如通过不应该是通用的函数传递泛型参数(当使用object可能是过度杀手或缓慢,如果你需要值类型时),当你需要一个不透明的指针时,或者当你需要快速访问数组元素时,你在运行时找到它的规范(使用Array.InternalGetReference).由于CLR甚至不允许错误使用此类型,为什么不鼓励?它似乎不安全或任何东西......
我找到的其他用途TypedReference:
C#中的"Specializing"泛型(这是类型安全的):
static void foo<T>(ref T value)
{
//This is the ONLY way to treat value as int, without boxing/unboxing objects
if (value is int)
{ __refvalue(__makeref(value), int) = 1; }
else { value = default(T); }
}
Run Code Online (Sandbox Code Playgroud)
编写适用于通用指针的代码(如果误用,这是非常不安全的,但如果使用正确则快速且安全):
//This bypasses the restriction that you can't have a pointer to T,
//letting you write very high-performance generic code.
//It's dangerous if you don't know what you're doing, …Run Code Online (Sandbox Code Playgroud) 有谁知道答案和/或有关于它的意见?
由于元组通常不会很大,我认为使用结构比使用类更有意义.怎么说你?
C#的ref本地是使用称为托管指针的CLR功能实现的,它具有自己的一组限制,但幸运的是,不可变的不是其中之一.即如果你有一个托管指针类型的局部变量,那么在ILAsm中,完全有可能改变这个指针,使其成为"引用"另一个位置.(C++/CLI还将此功能公开为内部指针.)
在ref本地读取C#文档时,我觉得C#的ref本地是,即使基于CLR的托管指针,也不可重定位; 如果它们被初始化为指向某个变量,则不能使它们指向别的东西.我试过用了
ref object reference = ref some_var;
ref reference = ref other_var;
Run Code Online (Sandbox Code Playgroud)
和类似的结构,无济于事.
我甚至试图在IL中编写一个包含托管指针的小结构,就C#而言它是有效的,但是CLR似乎不喜欢在结构中有一个托管指针,即使在我的使用中它没有永远不会去堆.
是否真的不得不诉诸于使用IL或者递归来解决这个问题?(我正在实现一个数据结构,需要跟踪它的哪些指针被跟踪,完美使用托管指针.)
我无意中发现的事实是,索引器this[int index] { get; }的工作方式不同的结构数组比它的结构的列表.也就是说,索引器在T[]返回对数组内元素的引用的情况下,而索引器在List<T>返回元素的副本的情况下.
这是一个非常大的语义和性能差异,我很高兴能够T[]让我们解决性能限制List<T>.
但是,我对实际实施感到困惑.的代码为Array由此在.NET参考源如下:
Object IList.this[int index] {
get { return GetValue(index); }
set { SetValue(value, index); }
}
Run Code Online (Sandbox Code Playgroud)
其中GetValue定义如下:
public unsafe Object GetValue(int index)
{
if (Rank != 1)
throw new ArgumentException(Environment.GetResourceString("Arg_Need1DArray"));
Contract.EndContractBlock();
TypedReference elemref = new TypedReference();
InternalGetReference(&elemref, 1, &index);
return TypedReference.InternalToObject(&elemref);
}
Run Code Online (Sandbox Code Playgroud)
索引器的返回类型Object意味着将发生装箱.
所以我的问题是,当我访问T[]where T是struct 的元素时,我能确定不会发生装箱吗?
我假设编译器和/或CLR专门处理数组,并且实际上并不打扰索引器的签名.它是否正确?在某个地方有更全面的讨论吗?