sma*_*man 14 c# performance struct value-type non-nullable
我一直在使用结构作为隐式验证复杂值对象的机制,以及围绕更复杂类的通用结构以确保有效值.我对性能影响有点无知,所以我希望你们都能帮助我.例如,如果我要做一些事情,比如将域对象注入值类型包装器,会导致问题吗?为什么?我理解值类型和引用类型之间的区别,我的目标是利用值类型的不同行为.为了负责任地做到这一点,我到底需要考虑什么?
这是我正在思考的一个非常基本的想法.
public struct NeverNull<T>
where T: class, new()
{
private NeverNull(T reference)
{
_reference = reference;
}
private T _reference;
public T Reference
{
get
{
if(_reference == null)
{
_reference = new T();
}
return _reference;
}
set
{
_reference = value;
}
}
public static implicit operator NeverNull<T>(T reference)
{
return new NeverNull<T>(reference);
}
public static implicit operator T(NeverNull<T> value)
{
return value.Reference;
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 11
好吧,有一件令人讨厌的事情是,这并不像你想象的那样天真:
NeverNull<Foo> wrapper1 = new NeverNull<Foo>();
NeverNull<Foo> wrapper2 = wrapper1;
Foo foo1 = wrapper1;
Foo foo2 = wrapper2;
Run Code Online (Sandbox Code Playgroud)
这将创建两个实例,Foo因为在wrapper1创建实例之前复制了原始版本.
基本上,你正在处理一个可变的结构 - 这几乎不是一件好事.另外,我一般不热衷于隐式转换.
感觉就像你正试图在这里实现看起来很神奇的代码......而且我通常会反对这种事情.也许它对你的特定用例有意义,但我想不出我个人想要使用它的地方.
正如Jon正确指出的那样,这里的问题是类型的行为是意外的,而不是它很慢.从性能角度来看,围绕引用的struct wrapper的开销应该非常低.
如果你想要做的是表示一个不可为空的引用类型,那么struct是一种合理的方法.但是,我倾向于通过失去"自动创建"功能使结构不可变:
public struct NeverNull<T> where T: class
{
private NeverNull(T reference) : this()
{
if (reference == null) throw new Exception(); // Choose the right exception
this.Reference = reference;
}
public T Reference { get; private set; }
public static implicit operator NeverNull<T>(T reference)
{
return new NeverNull<T>(reference);
}
public static implicit operator T(NeverNull<T> value)
{
return value.Reference;
}
}
Run Code Online (Sandbox Code Playgroud)
让呼叫者负责提供有效的参考; 如果他们想要"新"一个,那就让他们吧.
另请注意,通用转换运算符可以为您提供意外结果.您应该阅读转换运算符的规范并彻底理解它.例如,你不能围绕"对象"创建一个非null包装器,然后将该事物隐式转换为展开转换; 每个对对象的隐式转换都将在struct上进行装箱转换.您不能"替换"C#语言的内置转换.