未知のタイプへのボックス化解除
-
03-10-2019 - |
質問
タイプ自体が不明な場合、積分タイプ(短い/int/long)を本質的なタイプに解除することをサポートする構文を把握しようとしています。
これは、概念を示す完全に不自然な例です。
// 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が何であるかわからない場合でも)」と書かれた何らかの形式の構文があるはずです。オブジェクトは最終的に同じソースから来るため、実際にはミスマッチがありません(短い!=ロング)。
不自然な例をお詫びします。これは、構文を示すための最良の方法のように思えました。
ありがとう。
解決
さて、 object
それ自体がフレームワークが知っている最も一般的なタイプです。箱入りの値のタイプ(原始を含む)または他の何かが重要ではないかどうか。あなたがより具体的にあなたを取得したいなら 持ってる あなたが「ゆるくタイプされた」世界にとどまらない限り、タイプキャストをするために 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
;まだオブジェクトの参照ですが、元の構造またはプリミティブタイプにも強く入力されています。
他のヒント
これで何を達成したいかについては完全にはわかりませんが、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.ToInt32(SomeObject);
何か違うことを意味する場合は、投稿を明確にしてください(編集ボタンを押して編集してください)。
ちなみに、からの変換 object
すべてのベースタイプであるため、非常にエラーが発生しやすい場合があります。だから、 object
何でもすることができます、そしてそれはあなたが常に安全に変換することができないことを意味します object
INTまたはその他のタイプに。
その他の例:
int value;
try
{
value = Convert.ToInt32(someObject);
}
catch (FormatException)
{
// the convertion is unsuccessful
}
そしてこれも便利です:
int myValue;
if (!int.TryParse(something, out myValue))
{
//unsuccessful
}
これが役立つことを願っています。
返すことができます dynamic
, 、その後、積分タイプにキャストできます。
他の人が述べているように、各方法から長い値を返すため、例は機能しません。したがって、ここで無効なキャスト例外が得られます(箱入りのロングは短くすることはできません)。
newData.ShortVale = (short)data.GetBoxedShortValue();
ただし、C#4を使用しています dynamic
, 、これは機能します(getBoxedメソッドの修正に注意し、 dynamic
それよりも object
:
// 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
}
最後の3つのケースでは、キャストは必要ないことに注意してください。ただし、タイプが揃っていない場合、 GetBoxedShortValue() { return LongValue; }
, 、最後の3行は、キャストの例外が無効になります。 (興味深いことに、最初の3つはしません、彼らはただ機能しますが、あなたが変えたとき dynamic
に戻る object
, 彼ら 無効なキャストの例外を投げます。)