C# 取消装箱到未知类型
我试图找出当类型本身未知时,支持将整型(short/int/long)解包为其内在类型的语法 下面是一个完全人为设计的示例,演示了该概念:C# 取消装箱到未知类型,c#,.net,object,unboxing,inferred-type,C#,.net,Object,Unboxing,Inferred Type,我试图找出当类型本身未知时,支持将整型(short/int/long)解包为其内在类型的语法 下面是一个完全人为设计的示例,演示了该概念: // Just a simple container that returns values as objects struct DataStruct { public short ShortVale; public int IntValue; public long LongValue; public object GetBoxedS
// Just a simple container that returns values as objects
struct DataStruct
{
public short ShortVale;
public int IntValue;
public long LongValue;
public object GetBoxedShortValue() { return ShortVale; }
public object GetBoxedIntValue() { return IntValue; }
public object GetBoxedLongValue() { return LongValue; }
}
static void Main( string[] args )
{
DataStruct data;
// Initialize data - any value will do
data.LongValue = data.IntValue = data.ShortVale = 42;
DataStruct newData;
// This works if you know the type you are expecting!
newData.ShortVale = (short)data.GetBoxedShortValue();
newData.IntValue = (int)data.GetBoxedIntValue();
newData.LongValue = (long)data.GetBoxedLongValue();
// But what about when you don't know?
newData.ShortVale = data.GetBoxedShortValue(); // error
newData.IntValue = data.GetBoxedIntValue(); // error
newData.LongValue = data.GetBoxedLongValue(); // error
}
在每种情况下,整数类型都是一致的,因此应该有某种形式的语法表示“对象包含一个简单的X类型,将其返回为X(尽管我不知道X是什么)”。因为对象最终来自同一个源,所以不可能存在不匹配(short!=long)
我为这个人为的例子道歉,它似乎是演示语法的最佳方式
谢谢。您可以返回
dynamic
,然后可以将其转换为整数类型。嗯,对象本身就是框架知道的最通用的类型。是装箱值类型(包括原语)还是其他类型并不重要;如果你想变得更具体,你必须进行类型转换,除非你仍然使用object
(或者,在C#4中,dynamic
)处于“松散类型”的世界中
但是,请注意,您可以使用条件列表来实现您想要的:
object boxedValue = GetBoxedValue();
if (typeof(short) == boxedValue.GetType()) {
newData.ShortValue = (short)boxedValue;
} else if (typeof(int) == boxedValue.GetType()) {
newData.IntValue = (int)boxedValue;
} else if (typeof(long) == boxedValue.GetType()) {
newData.LongValue = (long)boxedValue;
} else {
// not one of those
}
public class Box<T>: IConvertible where T: struct, IConvertible {
public static implicit operator T(Box<T> boxed) {
return boxed.Value;
}
public static explicit operator Box<T>(T value) {
return new Box<T>(value);
}
private readonly T value;
public Box(T value) {
this.value = value;
}
public T Value {
get {
return value;
}
}
public override bool Equals(object obj) {
Box<T> boxed = obj as Box<T>;
if (boxed != null) {
return value.Equals(boxed.Value);
}
return value.Equals(obj);
}
public override int GetHashCode() {
return value.GetHashCode();
}
public override string ToString() {
return value.ToString();
}
bool IConvertible.ToBoolean(IFormatProvider provider) {
return value.ToBoolean(provider);
}
char IConvertible.ToChar(IFormatProvider provider) {
return value.ToChar(provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider) {
return value.ToSByte(provider);
}
byte IConvertible.ToByte(IFormatProvider provider) {
return value.ToByte(provider);
}
short IConvertible.ToInt16(IFormatProvider provider) {
return value.ToInt16(provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider) {
return value.ToUInt16(provider);
}
int IConvertible.ToInt32(IFormatProvider provider) {
return value.ToInt32(provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider) {
return value.ToUInt32(provider);
}
long IConvertible.ToInt64(IFormatProvider provider) {
return value.ToInt64(provider);
}
ulong IConvertible.ToUInt64(IFormatProvider provider) {
return value.ToUInt64(provider);
}
float IConvertible.ToSingle(IFormatProvider provider) {
return value.ToSingle(provider);
}
double IConvertible.ToDouble(IFormatProvider provider) {
return value.ToDouble(provider);
}
decimal IConvertible.ToDecimal(IFormatProvider provider) {
return value.ToDecimal(provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider) {
return value.ToDateTime(provider);
}
string IConvertible.ToString(IFormatProvider provider) {
return value.ToString(provider);
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider) {
return value.ToType(conversionType, provider);
}
}
编辑:通用“框”也可以执行您想要的操作:
object boxedValue = GetBoxedValue();
if (typeof(short) == boxedValue.GetType()) {
newData.ShortValue = (short)boxedValue;
} else if (typeof(int) == boxedValue.GetType()) {
newData.IntValue = (int)boxedValue;
} else if (typeof(long) == boxedValue.GetType()) {
newData.LongValue = (long)boxedValue;
} else {
// not one of those
}
public class Box<T>: IConvertible where T: struct, IConvertible {
public static implicit operator T(Box<T> boxed) {
return boxed.Value;
}
public static explicit operator Box<T>(T value) {
return new Box<T>(value);
}
private readonly T value;
public Box(T value) {
this.value = value;
}
public T Value {
get {
return value;
}
}
public override bool Equals(object obj) {
Box<T> boxed = obj as Box<T>;
if (boxed != null) {
return value.Equals(boxed.Value);
}
return value.Equals(obj);
}
public override int GetHashCode() {
return value.GetHashCode();
}
public override string ToString() {
return value.ToString();
}
bool IConvertible.ToBoolean(IFormatProvider provider) {
return value.ToBoolean(provider);
}
char IConvertible.ToChar(IFormatProvider provider) {
return value.ToChar(provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider) {
return value.ToSByte(provider);
}
byte IConvertible.ToByte(IFormatProvider provider) {
return value.ToByte(provider);
}
short IConvertible.ToInt16(IFormatProvider provider) {
return value.ToInt16(provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider) {
return value.ToUInt16(provider);
}
int IConvertible.ToInt32(IFormatProvider provider) {
return value.ToInt32(provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider) {
return value.ToUInt32(provider);
}
long IConvertible.ToInt64(IFormatProvider provider) {
return value.ToInt64(provider);
}
ulong IConvertible.ToUInt64(IFormatProvider provider) {
return value.ToUInt64(provider);
}
float IConvertible.ToSingle(IFormatProvider provider) {
return value.ToSingle(provider);
}
double IConvertible.ToDouble(IFormatProvider provider) {
return value.ToDouble(provider);
}
decimal IConvertible.ToDecimal(IFormatProvider provider) {
return value.ToDecimal(provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider) {
return value.ToDateTime(provider);
}
string IConvertible.ToString(IFormatProvider provider) {
return value.ToString(provider);
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider) {
return value.ToType(conversionType, provider);
}
}
公共类框:IConvertible,其中T:struct,IConvertible{
公共静态隐式运算符T(方框){
返回装箱。值;
}
公共静态显式运算符框(T值){
返回新框(值);
}
私有只读T值;
公用箱(T值){
这个值=值;
}
公共价值{
得到{
返回值;
}
}
公共覆盖布尔等于(对象对象对象){
装箱=obj作为箱子;
如果(已装箱!=null){
返回值.Equals(装箱的.value);
}
返回值。等于(obj);
}
公共覆盖int GetHashCode(){
返回值。GetHashCode();
}
公共重写字符串ToString(){
返回值.ToString();
}
bool IConvertible.ToBoolean(IFormatProvider提供程序){
返回值.ToBoolean(提供程序);
}
char IConvertible.ToChar(IFormatProvider){
返回值.ToChar(提供者);
}
sbyte IConvertible.ToSByte(IFormatProvider){
返回值.ToSByte(提供程序);
}
字节IConvertible.ToByte(IFormatProvider){
返回值.ToByte(提供程序);
}
短IConvertible.ToInt16(IFormatProvider){
返回值.ToInt16(提供程序);
}
ushort IConvertible.ToUInt16(IFormatProvider){
返回值.ToUInt16(提供者);
}
int IConvertible.ToInt32(IFormatProvider){
返回值.ToInt32(提供程序);
}
uint IConvertible.ToUInt32(IFormatProvider提供程序){
返回值.ToUInt32(提供程序);
}
long IConvertible.ToInt64(IFormatProvider){
返回值.ToInt64(提供程序);
}
ulong IConvertible.ToUInt64(IFormatProvider提供程序){
返回值.ToUInt64(提供程序);
}
浮点IConvertible.ToSingle(IFormatProvider){
返回值.ToSingle(提供程序);
}
双IConvertible.ToDouble(IFormatProvider){
返回值.ToDouble(提供程序);
}
十进制IConvertible.ToDecimal(IFormatProvider提供程序){
返回值.ToDecimal(提供程序);
}
DateTime IConvertible.ToDateTime(IFormatProvider提供程序){
返回值.ToDateTime(提供程序);
}
字符串IConvertible.ToString(IFormatProvider提供程序){
返回值.ToString(提供程序);
}
对象IConvertible.ToType(类型转换类型,IFormatProvider提供程序){
返回值.ToType(conversionType,provider);
}
}
然后可以使用它来代替对象
;它仍然是一个对象引用,但它也是原始结构或基元类型的强类型。我不完全确定您希望用它实现什么,但您的数据结构类型是错误的
我想,并不是所有的方法都返回LongValue
struct DataStruct
{
public short ShortVale;
public int IntValue;
public long LongValue;
public object GetBoxedShortValue() { return ShortVale; }
public object GetBoxedIntValue() { return IntValue; }
public object GetBoxedLongValue() { return LongValue; }
}
否则,您可以始终使用Convert类尝试在不同类型之间进行转换。
例如:
Convert.ToInt32(SomeObject);
如果你的意思不同,请澄清你的帖子(只需点击编辑按钮并编辑它)
顺便说一下,从对象
转换可能非常容易出错,因为它是所有内容的基本类型。因此,对象
可以是任何东西,这意味着您不能总是安全地将对象
转换为int或任何其他类型
更多示例:
int value;
try
{
value = Convert.ToInt32(someObject);
}
catch (FormatException)
{
// the convertion is unsuccessful
}
这也很有用:
int myValue;
if (!int.TryParse(something, out myValue))
{
//unsuccessful
}
我希望这会有所帮助。正如其他人所说,您的示例将不起作用,因为您从每个方法返回LongValue,因此您将在这里得到一个无效的强制转换异常(装箱的long不能强制转换为short)
但是,使用C#4的dynamic
,这将起作用(注意对GetBoxed方法和dynamic
的修复,而不是对象的修复):
// Just a simple container that returns values as objects
struct DataStruct
{
public short ShortVale;
public int IntValue;
public long LongValue;
public dynamic GetBoxedShortValue() { return ShortValue; }
public dynamic GetBoxedIntValue() { return IntValue; }
public dynamic GetBoxedLongValue() { return LongValue; }
}
static void Main( string[] args )
{
DataStruct data;
// Initialize data - any value will do
data.LongValue = data.IntValue = data.ShortVale = 42;
DataStruct newData;
newData.ShortVale = (short)data.GetBoxedShortValue();
newData.IntValue = (int)data.GetBoxedIntValue();
newData.LongValue = (long)data.GetBoxedLongValue();
newData.ShortVale = data.GetBoxedShortValue(); // ok
newData.IntValue = data.GetBoxedIntValue(); // ok
newData.LongValue = data.GetBoxedLongValue(); // ok
}
请注意,在最后三种情况下不需要任何强制转换。但是,请注意,如果类型不对齐,如在GetBoxedShortValue(){return LongValue;}
中,最后三行将导致无效的强制转换异常。(有趣的是,前三种方法不起作用,它们只起作用,但当您将dynamic
更改回object
时,它们将抛出无效的强制转换异常。)所有GetBoxed
方法都返回LongValue
。输入错误?什么意思是“不可能存在不匹配”?如果您知道类型,则不可能;如果您不知道,则可能存在。您希望如何使用取消装箱的结果?如果您在取消装箱后不知道类型,则无法对其执行任何操作(除了猜测和使用动态
)。如果在取消装箱后确实知道该类型,则取消装箱到该类型。在您的示例中,您知道newData.IntValue只能分配一个