Я пытаюсь выяснить синтаксис, который поддерживает распаковывание целочисленного типа (короткого/международного/длинного) к его внутреннему типу, когда сам тип неизвестен.
Вот полностью изобретенный пример, который демонстрирует понятие:
// 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)". Поскольку объекты в конечном счете прибывают из того же источника, действительно не может быть несоответствия (короткий! = долго).
Я приношу извинения за изобретенный пример, он походил на лучший способ продемонстрировать синтаксис.
Спасибо.
Что ж, объект
сам по себе является наиболее общим типом, известным фреймворку. Является ли это типом значения в штучной упаковке (включая примитивный) или что-то еще, не имеет значения; если вы хотите уточнить, у вас есть , чтобы выполнить приведение типов, если вы не остаетесь в «слабо типизированном» мире с объектом
(или, в C # 4, динамическим
]).
Обратите внимание, однако, что вы можете использовать список условий для достижения того, чего хотите:
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);
}
}
Затем его можно использовать вместо из объекта
; это по-прежнему ссылка на объект, но она также строго типизирована для исходной структуры или примитивного типа.
Я не совсем уверен, что вы Я бы хотел добиться этого, но ваш тип DataStruct ошибочен.
Я полагаю, не все его методы возвращают 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 из каждого метода, поэтому вы получите недопустимое исключение приведения здесь (заключенное в коробку длинное не может быть преобразовано в короткое).
newData.ShortVale = (short)data.GetBoxedShortValue();
Однако, используя динамический
C # 4, это будет работать (обратите внимание на исправления для ваших методов GetBoxed и динамического
, а не объекта
:
// 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
обратно на объект
, они выбросят недопустимые исключения приведения типов.)
Вы можете вернуть dynamic
, который затем может быть приведен к целочисленному типу.