首先,两个例子:
// This works
int foo = 43;
long lFoo = foo;
// This doesn't
object foo = (int)43;
long? nullFoo = foo as long?; // returns null
long lFoo = (long)foo; // throws InvalidCastException
if (foo.GetType() == typeof(int))
Console.WriteLine("But foo is an int..."); // This gets written out
Run Code Online (Sandbox Code Playgroud)
现在,我猜测为什么第二个不起作用是因为拳击.此代码背后的目的是实现IComparable.我需要一些方法来强制将对象强制转换为long或ulong,或者如果不是,则抛出错误.我不想为每个基本的数字类型(byte,int,long,ubyte,...)实现检查.我宁愿用最大的数字类型捕获它们并以这种方式处理它.这里所有聪明人的想法?我怎样才能取消打开对象,最好避免反射,但我想如果这是唯一的方法......或者我应该不实现非泛型版本IComparable?
编辑:
这似乎有效,但似乎是一个可怕的黑客围绕这个问题.只有我吗?
long lFoo = long.Parse(foo.ToString());
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一些代码来将数据从对象类型字段(来自DataSet)转换为它的目标(类型)字段.我正在使用动态转换(至少尝试)它.它似乎适用于字符串,int,DateTime.
但它不适用于无符号类型(ulong,uint).下面是一个简单的代码,显示了我想要做的事情.如果将ul var类型从ulong更改为int,则可以正常工作.
有人有线索吗?
public class console
{
public static void CastIt<T>(object value, out T target)
{
target = (T) value;
}
public static void Main()
{
ulong ul;
string str;
int i;
DateTime dt;
object ul_o = (object) 2;
object str_o = (object) "This is a string";
object i_o = (object)1;
object dt_o = (object) DateTime.Now;
Console.WriteLine("Cast");
CastIt(ul_o, out ul);
CastIt(str_o, out str);
CastIt(i_o, out i);
CastIt(dt_o, out dt);
Console.WriteLine(ul);
Console.WriteLine(str);
Console.WriteLine(i);
Console.WriteLine(dt.ToString());
}
}
Run Code Online (Sandbox Code Playgroud) 我创建了以下属性,它抛出InvalidCastException,如果当吸气剂访问ViewState[TOTAL_RECORD_COUNT]了null.
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
Run Code Online (Sandbox Code Playgroud)
我的想法是它错误地尝试将对象拆箱ViewState[TOTAL_RECORD_COUNT]到一个int,因为它包含了一个失败long,但我认为这个逻辑可能存在缺陷.我将把它作为练习留给读者指出这个缺陷.
我已经改变了那个属性来阅读
public long TotalRecordCount
{
get { return (long?)ViewState[TOTAL_RECORD_COUNT] ?? -1; }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
Run Code Online (Sandbox Code Playgroud)
这只是膨胀.不过,我仍然想知道我的原始版本有什么问题... StackOverflow救援?
请注意,如果我尝试(long)(ViewState[TOTAL_RECORD_COUNT] ?? -1)在立即窗口中执行,我会收到错误消息Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long',如果我执行,(ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().Name我会得到Int32.我可以执行(long)-1并以-1结束Int64......所以这是什么?
从MSDN我读到装箱/拆箱用于将值类型视为对象.但是当我读到关于ArrayList的内容时,它会读到它也会装箱.所以我很困惑,因为ArrayList将值和引用类型保存为对象.另外,在术语方面,以下不是拆箱,它只是铸造?
ArrayList a=new ArrayList();
a.Add(someClass);
someClass x=(someClass)a[0];
Run Code Online (Sandbox Code Playgroud) 以下代码导致InvalidCastException.
object x = (short) 1;
int y = (int) x;
Run Code Online (Sandbox Code Playgroud)
我知道我可以x先进行a short然后进入a int,虽然这不是一个选项,因为盒装值的类型是未知的(但它确实小于a int).
如果拆箱到比盒装类型更大的类型,我该如何处理异常?
编辑:
我通过使用dynamic类型解决了我的问题(具有所有性能影响)
假设以下代理"调用者"签名:
FuncCaller<T>(Func<T, bool> predicate)
Run Code Online (Sandbox Code Playgroud)
和匹配方法:
bool MyFunc(object o)
Run Code Online (Sandbox Code Playgroud)
什么时候T是引用类型,我可以像这样MyFunc 隐式调用:
FuncCaller<String>(MyFunc) // valid
Run Code Online (Sandbox Code Playgroud)
相反,如果T是值类型,则在隐式调用MyFunc时会出现编译错误:
FuncCaller<Int32>(MyFunc) // invalid ("No overload for 'MyFunc(object)' matches delegate 'System.Func<int?,bool>'")
Run Code Online (Sandbox Code Playgroud)
我的问题是,鉴于这两个例子,为什么MyFunc在隐式调用时调用无效,但在明确调用时有效如下:
FuncCaller<Int32>(i => MyFunc(i)) // valid
Run Code Online (Sandbox Code Playgroud)
我认为这是与拳击和拆箱类型相关的某种问题?
该解决方案首先需要unbox该值,然后才将其转换为另一种类型.然而,盒装值"知道"它自己的类型,我认为没有理由不能调用转换运算符.
此外,同样的问题对参考类型有效:
void Main()
{
object obj = new A();
B b = (B)obj;
}
public class A
{
}
public class B {}
Run Code Online (Sandbox Code Playgroud)
这段代码抛出InvalidCastException.所以这不是价值与参考类型的问题 ; 这是编译器的行为方式.
对于它发出的上层代码castclass B,以及代码
void Main()
{
A obj = new A();
B b = (B)obj;
}
public class A
{
public static explicit operator B(A obj)
{
return new B();
}
}
public class B
{
}
Run Code Online (Sandbox Code Playgroud)
它会散发出来call A.op_Explicit.
啊哈!编译器看到它 …
虽然在第91页上简单地阅读了关于装箱和拆箱的c#,但作者写道:
拳击转换对于提供统一类型系统至关重要.该系统并不完美,但我们将在泛型中看到,与数组和泛型的差异仅支持**引用转换**而不支持**装箱转换**
并引用示例代码:
object [] a1 = new string [3]; //legal
object [] a2 = new int [3]; // error
Run Code Online (Sandbox Code Playgroud)
有人可以解释作者试图提供的内容以及为什么第一行是合法的而第二行不是?
根据我的理解,Java自动处理Autoboxing和Unboxing,即将Primitives转换为Object Wrappers,反之亦然.但是,取消装箱似乎不适用于下面的代码.
public class TestMath {
public static void main(String[] args) {
Long resultLong = (Long) Math.pow(10, 10);
System.out.println(resultLong);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码给我的编译错误,直到我做手工拆箱通过更换(长)与(长).我想了解这背后的原因.
编译错误如下所示:
线程"main"中的异常java.lang.Error:未解决的编译问题:无法从double转换为Long
enum Season { spring, summer, fall, winter }
int a = (int)Season.spring;
Run Code Online (Sandbox Code Playgroud)
这是拆箱还是普通的铸造?如果这是拆箱,您能解释一下原因吗?我认为这只是一个正常的转换,因为“enum”和“int”都是值类型数据。