我做了以下扩展方法......
public static class ObjectExtensions
{
public static T As<T>(this object pObject, T pDefaultValue)
{
if (pObject == null || pObject == DBNull.Value)
return pDefaultValue;
return (T) pObject;
}
}
Run Code Online (Sandbox Code Playgroud)
...我用于例如读取这样的数据:
string field = datareader["column"].As("default value when null")
Run Code Online (Sandbox Code Playgroud)
但是当我想从装箱值转换为可为空的枚举时,它不起作用。我能想到的最好的就是这个(无效的杂乱 WIP 代码):
public static class ObjectExtensions
{
public static T As<T>(this object pObject, T pDefaultValue)
{
if (pObject == null || pObject == DBNull.Value)
return pDefaultValue;
var lType = typeof (T);
if (!IsNullableEnum(lType))
return (T) pObject;
var lEnumType = Nullable.GetUnderlyingType(lType);
var …Run Code Online (Sandbox Code Playgroud) 有2个和3个装箱/拆箱的例子吗?
1)文档示例:
int i = 123;
object iBoxed = i;
i = (int) iBoxed;
Run Code Online (Sandbox Code Playgroud)
2:拳击/拆箱也是吗?
int i = 123;
object iBoxed = i;
i = Int32.Parse(iBoxed.ToString());
Run Code Online (Sandbox Code Playgroud)
3:拳击/拆箱也是吗?
int i = 123;
object iBoxed = i;
i = Convert.ToInt32(iBoxed);
Run Code Online (Sandbox Code Playgroud)
我假设在所有例子中技术上都是一样的.
所以我猜2和3是拳击/拆箱的例子?
如果您运行以下代码,
public class Foo{
public static void main(String[] args){
int id = new Bar().getId(); // throws unexpected NullPointerException
}
private static class Bar{
private final Integer id;
public Bar(){
this(null);
}
public Bar(Integer id){
this.id = id;
}
public Integer getId(){
return id;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您将获得以下堆栈跟踪,
Exception in thread "main" java.lang.NullPointerException
at Foo.main(Foo.java:3)
Run Code Online (Sandbox Code Playgroud)
为什么没有编译器警告或任何东西?恕我直言,这是一个非常讨厌的微妙与拆箱,或者也许我只是天真.
添加@Javier提供的答案,如果您使用的是Eclipse,则需要执行以下操作来启用此功能:
我试图调试性能问题作为更复杂的代码的一部分.似乎append我用来创建动态的,可增长的向量的(Int,Int,Int,Int)函数导致Int元组中的一个在被写入向量之前被装箱和取消装箱.我写了一个更简单的代码来重现这个问题 - 它似乎只有在我在append函数中添加向量增长功能时才会发生- 下面的示例代码(除了重现问题之外它没有做太多有用的工作),其后的片段core显示了值被装箱和取消装箱:
{-# LANGUAGE BangPatterns #-}
module Test
where
import Data.Vector.Unboxed.Mutable as MU
import Data.Vector.Unboxed as U hiding (mapM_)
import Control.Monad.ST as ST
import Control.Monad.Primitive (PrimState)
import Control.Monad (when)
import GHC.Float.RealFracMethods (int2Float)
import Data.STRef (newSTRef, writeSTRef, readSTRef)
import Data.Word
type MVI1 s = MVector (PrimState (ST s)) Int
type MVI4 s = MVector (PrimState (ST s)) (Int,Int,Int,Int)
data Snakev s = S {-# UNPACK #-}!Int
!(MVI4 s)
newVI1 …Run Code Online (Sandbox Code Playgroud) struct Point
{
public int x;
public int y;
}
void Main()
{
Point p;
p.x = 1;
p.y = 1;
Object o = p;
((Point) o).x = 4; // error
((Point) o).x = 5; // error
((Point) o).x = 6; // error
p = (Point) o // expect 6
}
Run Code Online (Sandbox Code Playgroud)
为什么不编译
ldloc.1 // o
unbox Point
ldc.i4.4
stfld Point.x
Run Code Online (Sandbox Code Playgroud)
C++ CLI允许的地方.
我最近尝试运行以下两段代码,并对输出感到惊讶.
第一:
// ...
System.out.println( (Boolean)null || true );
// ...
Run Code Online (Sandbox Code Playgroud)
第二:
// ...
System.out.println( (Boolean)null || false );
// ...
Run Code Online (Sandbox Code Playgroud)
第一个示例导致以下输出:
true
第二个示例导致以下输出:
com.blah.main
中线程"main"java.lang.NullPointerException
中的异常(SanityCheck.java:26)
我原以为这两个例子都会导致空指针异常,因为任何短路都是从左到右应用的.从布尔值中取消装箱布尔值的尝试应该在逻辑的另一侧或考虑之前失败.
谁能解释这种不一致的行为?
我明白拳击是什么.值类型被装箱到对象/引用类型,然后作为对象存储在托管堆上.但是我不能通过拆箱来解决问题.
取消装箱会将对象/引用类型转换回值类型
int i = 123; // A value type
object box = i; // Boxing
int j = (int)box; // Unboxing
Run Code Online (Sandbox Code Playgroud)
好的.但是,如果我尝试将值类型拆分为另一个值类型,例如,在上面的示例中,它会抛出InvalidCastException
long d = (long)box;
Run Code Online (Sandbox Code Playgroud)
它让我有一个想法,可能是运行时隐式知道"box"对象中框内的实际TYPE值类型.如果我是对的,我想知道这种类型信息的存储位置.
编辑:
因为int可以隐式转换为long.这让我很困惑.
int i = 123;
long lng = i;
Run Code Online (Sandbox Code Playgroud)
非常好,因为它没有涉及拳击/拆箱.
更新:
海因兹是对的.AutoCAD Polyline是引用类型,而不是结构.好点子.但我简化了场景,因为我在实际应用程序中处理的是一个AutoCAD对象,它是struct.所以请将两者都视为struct而不是引用类型.
我正在寻找正确的方法来应对这种情况,如果有人能够阐明或帮助我更好地理解,我将不胜感激.
数据访问层中有一个接口,有两个实现来处理两个不同的提供程序:AutoCad和Sketchup API.
interface IEntity
{
void object GetPoly();
void void InsertPoly(object poly);
}
class AutocadEntity
{
void object GetPoly()
{
//calling Autocad APIs
return Autocad Polyline object
}
void InsertPoly(object poly){...}
}
Run Code Online (Sandbox Code Playgroud)
GetPoly的Autocad实现将返回Polyline对象,因为这是在Autocad API中定义为折线,而Sketchup将返回Face对象.
我已经将返回类型(和参数)定义为对象来处理这些不同的类型.成本是拳击/拆箱发生时的性能问题.并且它更大胆地显示返回/参数是object []的位置.
我首先想知道方法返回/参数类型泛型是解决方案,但我认为它不会是因为实现是特定于类型的.
当取消装箱时,将盒装值的副本转换为适当的变量类型,但是在堆上的盒装副本的内存位置会发生什么.盒装副本是否保留在该位置并覆盖堆上的内存?
我有这个方法:
private static Dossier PrepareDossier(List<List<object>> rawDossier)
{
return new Dossier((int)rawDossier[0][0]);
}
Run Code Online (Sandbox Code Playgroud)
当我使用它时,我得到了一个InvalidCastException.但是,当我使用Convert.ToInt32(rawDossier[0][0])它时工作得很好.问题是什么?