30

I'm looking for a way to write code that tests whether a value is boxed.

My preliminary investigations indicate that .NET goes out of its way to conceal the fact, meaning that GetType() and IsValueType don't reveal the difference between a boxed value and an unboxed value. For example, in the following LinqPad C# expressions, I have faith that o1 is boxed and i1 is not boxed, but I would like a way to test it in code, or, second best, a way to know FOR SURE when looking at any variable or value, even if its type is "dynamic" or "object," whether it's boxed or not boxed.

Any advice?

// boxed? -- no way to tell from these answers!
object o1 = 123;
o1.GetType().Dump("o1.GetType()");
o1.GetType().IsValueType.Dump("o1.GetType().IsValueType");

// not boxed? -- no way to tell from these answers!
int i1 = 123;
i1.GetType().Dump("i1.GetType()");
i1.GetType().IsValueType.Dump("i1.GetType().IsValueType");
Abel
  • 56,041
  • 24
  • 146
  • 247
Reb.Cabin
  • 5,426
  • 3
  • 35
  • 64
  • 11
    I am wondering why it matters to you? How will you treat a 'boxed' or 'unboxed' object differently? – Cos Callis Apr 27 '11 at 15:52
  • 1
    @Cos: Boxing has performance implications. – Robert Harvey Apr 27 '11 at 16:01
  • you could generate an InvalidCastException inline using some int operator, then catch it. If you try and make it into a function boxing/unboxing will occur on the call. – Jodrell Apr 27 '11 at 16:26
  • 1
    @Jodrell -- could you elaborate on your suggestion please, perhaps by sketching some code? – Reb.Cabin Apr 27 '11 at 16:41
  • 1
    @Robert, @Rep... while it looks like you have a good answer, I am still intrigued with the question of "why". Yes, it has performance implications, but that is a design time decision. How will an object be treated differently at runtime if it is or isn't boxed? Are you planning to use something like: `if(oThing.isBoxed) {//do this;} else {//do that;}`?? – Cos Callis Apr 27 '11 at 17:24
  • 1
    @Cos: The purpose is to `Assert()` if the value being passed in by a caller is boxed. The use case is a high-performance library, such that performance degrades if boxed values are used. – Robert Harvey Apr 27 '11 at 19:26
  • 3
    Forgive me if I seem flippant, but those of you who see no value in exploring this have literally "boxed" yourselves. How can you be creative in your software development efforts if you can't see beyond the walls of your box? – Robert Harvey Apr 27 '11 at 20:16

10 Answers10

38

Try the following

public static bool IsBoxed<T>(T value)
{
    return 
        (typeof(T).IsInterface || typeof(T) == typeof(object)) &&
        value != null &&
        value.GetType().IsValueType;
}

By using a generic we allow the function to take into account both the type of the expression as viewed by the compiler and it's underlying value.

Console.WriteLine(IsBoxed(42));  // False
Console.WriteLine(IsBoxed((object)42)); // True
Console.WriteLine(IsBoxed((IComparable)42));  // True

EDIT

A couple of people have asked for clarification on why this needs to be generic. And questioned why this is even needed at all, can't the developer just look at code and tell if a value is boxed? In an attempt to answer both those questions consider the following method signature

void Example<T>(T param1, object param2, ISomething param3) where T : ISomething {
  object local1 = param1;
  ISomething local2 = param1;
  ...
}

In this scenario any of the provided parameters or locals could potentially represent boxed values and could just as easily not be. It's impossible to tell by casual inspection, only an examination of a combination of the runtime type and the reference by which the value is held can determine that.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    Why calculate at runtime what is already known at compile time? – Allon Guralnek Apr 27 '11 at 16:09
  • 4
    @Allon because to know if a value is boxed you need both runtime and compile time information. This is especially important when dealing with nested generics – JaredPar Apr 27 '11 at 16:12
  • The caller must provide both the argument and the type-argument. The answer to the question will depend on how it's asked. Not very useful. – Ani Apr 27 '11 at 16:18
  • @JaredPar: I'm not sure what you mean, can you please give an example of when it's useful? – Allon Guralnek Apr 27 '11 at 16:20
  • @Ani, type inference in the compiler makes in very unlikely the user will have to provide the type argument. See all of the examples I wrote at the bottom – JaredPar Apr 27 '11 at 16:22
  • @Allon, see the `Console.WriteLine` samples. To know if the value is boxed you need to know both 1. how is it viewed in the runtime (via a reference / interface value) and 2. what is the actual runtime type of the referred to value. – JaredPar Apr 27 '11 at 16:23
  • @JaredPar: Yes, but in that case the user is providing it *implicitly*. In which case they already have the answer. – Ani Apr 27 '11 at 16:24
  • @Ani, not in a deeply nested generic. – JaredPar Apr 27 '11 at 16:24
  • @Ani, or more appropriately it is impossible to tell in an uninstantiated generic or simply with an interface reference in themselves whether or not it is holding a boxed value. – JaredPar Apr 27 '11 at 16:27
  • @JaredPar: Can you give me an example of the "deeply nested generic"? – Ani Apr 27 '11 at 16:27
  • @Ani, Lets say I had the following: `ISomething obj = GetAFoo();`. You can't look at `obj` and know if it's a boxed value or not. It can only be determined by examining the reference type and the runtime type of the underlying value – JaredPar Apr 27 '11 at 16:28
  • 1
    @JaredPar: But why _would_ you need to know if something is boxed or not? – Allon Guralnek Apr 27 '11 at 16:29
  • As for "it is impossible to tell in an uninstantiated generic or simply with an interface reference in themselves whether or not it is holding a boxed value", that is a completely different matter (but more sensible certainly). If you are really attempting to answer that question, I suggest clarifying that, and adding a `class` constraint on the type-parameter. – Ani Apr 27 '11 at 16:30
  • 3
    @Allon, in general I don't think it's particularly useful. But it is a valid question so I tried to provide the best answer. I could see how it would be value though in a `Debug.Assert` check in a **very** performance sensitive application to ensure it wasn't wasting memory with boxed values – JaredPar Apr 27 '11 at 16:32
  • @Ani, adding a `class` constraint would break my answer. The point is to allow any value to be tested from any context (including uninstantiated generics) – JaredPar Apr 27 '11 at 16:33
  • Ok I'm really not following you. In what case does it make to pass in a struct-type as the type-argument? If you do, you already know the answer at compile-time. The *only* possibly useful query I see here is finding out whether an expression of an interface-type / object / dynamic is a reference to a boxed struct or a "genuine" class. One wouldn't want to pass in a value-type type-argument in that case, yes? Or have I missed the point completely ("deeply nested generics")? I hope I don't seem argumentative; I'm just trying to understand how this method could be useful. Cheers. – Ani Apr 27 '11 at 16:39
  • @Ani, Consider the example I just added to my answer. `void Example(T param1)`. There are many ways you could invoke this method which cause the value to be boxed or not, consider these two: `Example(42)`, `Example(42)`. In the first `param1` will be unboxed while in the second `param1` will be boxed. – JaredPar Apr 27 '11 at 16:42
  • @JaredPar: yes, that's exactly my scenario -- I need to Debug.Assert not boxed in the "inner loop" of perf-critical code. – Reb.Cabin Apr 27 '11 at 16:45
  • In all of those cases, the answer is known at compile-time. – Ani Apr 27 '11 at 16:48
  • @JaredPar, @Reb: I really don't understand your `Debug.Assert(...)` case. No boxing will occur with it. Can you please explain what you mean or give an example? – Allon Guralnek Apr 27 '11 at 16:50
  • @Ani, it's known at the point `Example` is instantiated it's clear but it's not known at the point `param1` is used. The latter is much more useful when you're trying to guard against accidental boxing in the performance sensitive function which is actually using the value. – JaredPar Apr 27 '11 at 16:51
  • @Allon: hijacking JaredPar's example : public static void Example(T param1, object param2, IComparable param3) { Console.WriteLine ("Perf-Critical Code"); Console.WriteLine ("param1 is boxed? {0}", IsBoxed(param1)); Console.WriteLine ("param2 is boxed? {0}", IsBoxed(param2)); Console.WriteLine ("param3 is boxed? {0}", IsBoxed(param3)); } --- looks like only the generic case is relevant --- – Reb.Cabin Apr 27 '11 at 16:56
  • @Reb: How is that useful? What insight does it give you? How does it improve the performance of your 'Perf-Critial Code'? Is there any value to this check? Any gain whatsoever? – Allon Guralnek Apr 27 '11 at 17:00
  • 4
    @Allon: Assume I'm a library writer, and do not have access to all the code that might use my library. In Debug builds, I wish to advise users that they are incurring a perf penalty by passing boxed values to my library routine. I don't see a way to do this with static checks in my library. – Reb.Cabin Apr 27 '11 at 17:05
  • @Reb: If your library routine works on value types, accept only value types. Why even allow reference types for such a routine? If it's generic, use generic constraints. If it's not, use overloads. – Allon Guralnek Apr 27 '11 at 17:10
  • 1
    @Allon, if @Reb's routine uses interfaces there is no static solution. – JaredPar Apr 27 '11 at 17:16
  • @JaredPar: If @Reb's routine uses interfaces, then value types will always be boxed. I'd still like to see a concrete, real-world example that produces actual value (even if infinitesimal) by checking if a value is boxed. – Allon Guralnek Apr 27 '11 at 17:19
  • @Allon, yes all value types would be boxed and this is exactly what @Reb is protecting against. His example is writing a high performance library which degrades when using boxed values or one that depends on referential equality on interface values. There is no way to statically prevent value types from being used so the only fall back is to do a runtime check as a preventative mechanism. – JaredPar Apr 27 '11 at 17:26
  • @JaredPar: Again, I can't think of such a case. Can you give an example that's more than just syntactic proof? – Allon Guralnek Apr 27 '11 at 17:36
  • 1
    @Allon, I'm not sure what you're stuck on right now. It's perfectly reasonable to take the stand in an API that you don't want to deal with boxed values (something I likely won't ever do but that doesn't make it invalid). If you do take that stance then a solution like mine is pretty much the only option. – JaredPar Apr 27 '11 at 17:43
  • 3
    Btw, I think a better implementation would be `return !typeof(T).IsValueType && value != null && value.GetType().IsValueType;` It handles nll-references and cases where `T = System.ValueType`. – Ani Apr 27 '11 at 19:47
  • Note that it's not always possible to tell whether a null value is the result of boxing a value type or not. – kvb Apr 27 '11 at 23:09
  • 1
    @JaredPar: You still need `!typeof(T).IsValueType` rather than explicitly checking for object / interface types, yes? For example, this wont work when `T = System.ValueType`. – Ani Apr 28 '11 at 00:55
  • 2
    "It's perfectly reasonable to take the stand in an API that you don't want to deal with boxed values" No it's not. Not if you're willing to deal with reference types. Boxing is only a performance penalty compared to dealing directly with value types. – Random832 Apr 28 '11 at 01:26
  • 7
    @Random832 actually it is a reasonable stance if your constraints dictate it. Performance matters and boxing has a direct impact on performance. – JaredPar Apr 28 '11 at 15:14
  • @Ani is absolutely right in his last two comments. For example if you say `IsBoxed((ValueType)42)` or `IsBoxed((Enum)(DateTime.Today.DayOfWeek))`, the method gives an incorrect answer. Of course, as has been said already, in the case `IsBoxed((object)(new Nullable()))` the method has no chance of seeing where it got its null reference from (and your implementation chooses to return `false`). – Jeppe Stig Nielsen Jul 17 '15 at 06:33
7

Well, let's use the trick ...

What do we know?

  • Value-type variable gets boxed again and again when assigned into reference-type variable
  • Reference-type variable will not get boxed again ...

So we will just check whether it gets boxed again (into another object) ... so we compare references

isReferenceType will be false here, because we compare 2 objects on heap (one boxed in surelyBoxed, one boxed just in call to ReferenceEquals):

int checkedVariable = 123;     //any type of variable can be used here
object surelyBoxed = checkedVariable;
bool isReferenceType = object.ReferenceEquals(surelyBoxed, checkedVariable);

isReferenceType will be true here, because we compare 1 object on heap to itself:

object checkedVariable = 123;     //any type of variable can be used here
object surelyBoxed = checkedVariable;
bool isReferenceType = object.ReferenceEquals(surelyBoxed, checkedVariable);

This works for ANY type, not just for int and object

To put it into well-usable method:

    public static bool IsReferenceType<T>(T input)
    {
        object surelyBoxed = input;
        return object.ReferenceEquals(surelyBoxed, input);
    }

This method can be easily used like this:

int i1 = 123;
object o1 = 123;
//...
bool i1Referential = IsReferenceType(i1);  //returns false
bool o1Referential = IsReferenceType(o1);  //returns true
Marcel Toth
  • 10,716
  • 4
  • 22
  • 17
  • 4
    I think you have a good basic idea, however some mistakes: The ReferenceEquals()-method takes objects already, so both inputs are "surelyBoxed" if T is a value-type, and inversely none of them are boxed if T isn't. So the only thing you need is `public static bool IsReferenceType(T input){ return object.ReferenceEquals(input, input); }` (because if it boxes each argument will box separately - even if they are the same variable). – AnorZaken Feb 23 '15 at 18:25
  • @Anor, I think you're missing the point of his explanation. The fact they're boxed on the way in to ReferenceEquals is exactly what he's using to test. Think of his 'surelyBoxed' as 'manuallyBoxed' vs 'implicitlyBoxed' on the way in to ReferenceEquals. It however would work exactly the same if he had created two object variables outside, then sent them into ReferenceEquals. If they were already objects they would just be three refs to the same object. If they were value types, there would be two different boxed instances. Make sense? – Mark A. Donohoe May 22 '15 at 05:57
  • 1
    @MarqueIV no, I think you missed my point: The surelyBoxed variable is redundant - it has no effect on the result. I was simply suggesting that he can save 1 line of code. – AnorZaken May 26 '15 at 07:49
  • @Anor, I was about to argue no it isn't because without it, you'd be doing ReferenceEquals(input, input), but then it clicked that just as you said that would already do two different boxes for value types (and none for reference types) meaning when passing in the same variable to both parameters, ReferenceEquals is *already* essentially a NoBoxNeeded function. You're spot-on. – Mark A. Donohoe May 26 '15 at 08:51
4

GetType() and IsValueType don't reveal the difference between a boxed value and an unboxed value.

GetType is a sealed (non-virtual) method on System.Object. Calling this method on a value-type will definitely box it. Not even Nullable<T> is able to get around this - calling GetType on a nullable will return the underlying type if it has a value (boxed as the underlying type) or throw a NullReferenceException if it doesn't (boxed to null, can't dereference a null-reference).

when looking at any variable or value, even if its type is "dynamic" or "object," whether it's boxed or not boxed.

In general, if you have an expression that "holds" a value-type, the value of that expression will be a reference to a box unless the expression's compile-time type is of the value-type itself (generics are slightly more complicated). Common reference-types that can hold references to boxed structures are object, dynamic and interface-types.

Ani
  • 111,048
  • 26
  • 262
  • 307
  • I suppose Intellisense will tell me the static type of an expression, and if it's a value type, and thus that it's not boxed. Good. – Reb.Cabin Apr 27 '11 at 16:33
  • Can you elaborate on the Generics issue a bit -- how to tell whether an instantiation of a generic type is statically a value type? This seems related to the problem of writing a generic routine that has arithmetic operators in it ... I gather it's impossible because the compiler cannot generate code unless it knows whether the operators should be intrinsic operators on value types (like + and * on int) or should be operator overloads, which are methods on the type. – Reb.Cabin Apr 27 '11 at 16:36
  • Your last paragraph is the right answer, with the slight clarification that when using the generics the "compile time" type may not be determined until runtime. – supercat Jan 13 '12 at 21:51
3

Here are some simple helper methods to check if a variable is a boxed integer:

public static bool IsBoxed(object item)
{
    return true;
}

public static bool IsBoxed<T>(T item) where T : struct
{
    return false;
}

Just call IsBoxed(...) on your variable:

IsBoxed(o1) // evaluates to true
IsBoxed(i1) // evaluates to false

This accomplishes nothing, of course. Why exactly do you need to know if a value is boxed or not?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Allon Guralnek
  • 15,813
  • 6
  • 60
  • 93
  • 4
    surely the second could be `IsBoxed(T item) where T : struct`. – Random832 Apr 27 '11 at 16:04
  • @Random832: Good point, but to aid in the understanding of basic concepts like boxing, I'd rather keep it simple. – Allon Guralnek Apr 27 '11 at 16:08
  • 4
    @JSBangs, this answer won't be equivalent to mine because it only works for int's. Even with the edits this answer incorrectly flags the following as true: `IsBoxed("hello world");` – JaredPar Apr 27 '11 at 16:12
  • 7
    @JaredPar: The code above is not meant to be serious. It is meant to illustrate the uselessness of checking if a variable is boxed or not. It is equivalent to having a `bool IsProgramRunning { return true; }` method. Of course the answer is problematic, in the same way the question is. – Allon Guralnek Apr 27 '11 at 16:17
  • @Allon, oh I understand that. I was merely trying to correct @JSBangs assertion that mine and your answers would be equivalent by adding a simple constraint :) – JaredPar Apr 27 '11 at 16:18
  • 2
    @Allon -- that's cute: using overloads to probe the type system at compile time. The reason I need to know is to verify that certain perf-critical code is not operating on boxed values. Code may be semantically correct, but inadvertently introduce boxing via a circuitous route through methods and interfaces with a serious perf penalty in the "inner loops," which tend to be in the deepest bits of code and thus most vulnerable to an accidental boxing. I would like to write Debug code or even Contracts to assert that something is not boxed. – Reb.Cabin Apr 27 '11 at 16:40
  • 2
    @Reb: I think you still do not fully understand the concept of boxing. You don't need to have a runtime check to make sure no value types are boxed, since it's a decision the compiler makes based on your code. Checking at runtime is way too late! All you need to do in order to see if boxing is occurring is to look at your code. – Allon Guralnek Apr 27 '11 at 16:46
  • @Allon: what about the generic case Example(T param) { perf-critical-code }. Example(42) will pass an unboxed value, Example((Accident)42) will pass a boxed value. With a runtime debug check, I can tell that no user has accidentally called the code with an accidental boxing. I don't see how to guard against that case with a compile time check (assuming i'm a library writer and don't have access to all user code) – Reb.Cabin Apr 27 '11 at 17:02
  • @Reb: See the first comment of this answer. Accident averted. – Allon Guralnek Apr 27 '11 at 17:06
  • The only code you can have in an unconstrained generic method like that won't _do_ anything with the boxed object except copy a pointer around, which will hardly have a negative performance impact. If the user is boxing millions of ints in a loop outside your code, that's their performance problem not yours. – Random832 Apr 27 '11 at 17:12
  • @Allon: ok, i see; seems the "where T : struct" constraint is true even for built-in value types like int, so the constraint will statically catch users who call the generic inappropriately. Thanks for the help! I understand boxing better now. – Reb.Cabin Apr 27 '11 at 17:30
  • 9
    I don't understand the implementation of the first "IsBoxed". Suppose you pass it null. It returns true. But null is not a boxed anything. Suppose you pass it "hello". It returns true. But "hello" is not a boxed anything. If your point is that the question itself is bizarre, I take your point. But these methods do not do what they advertise. – Eric Lippert Apr 27 '11 at 20:10
  • @Eric - just to nitpick, `null` could be a boxed nullable. – kvb Apr 27 '11 at 22:40
  • 7
    @kvb: No, it could not. **There is no such thing as a "boxed nullable".** When a nullable int is boxed, it either becomes null, or it becomes a boxed int. It never becomes a "boxed nullable". No such animal. – Eric Lippert Apr 28 '11 at 01:50
  • @Eric - I apologize if I'm using terminology incorrectly here, but I find it hard to reconcile "null is not a boxed anything" with the fact that null can be unboxed to a `T?`. Likewise, even though boxing a non-null nullable results in a boxed value of the underlying type, to my mind this is by definition still a "boxed nullable" since it is a literally a nullable that has been boxed, even if that's not really a proper term. – kvb Apr 28 '11 at 02:20
  • 4
    @kvb: Imagine a room. The room contains a box. The box contains twelve oranges. Now imagine the same room, empty. The room does not contain a box at all. How many oranges are in the box in an empty room? The question is nonsensical because there is no box in an empty room. That's the difference between a boxed integer and a null reference. – Eric Lippert Apr 28 '11 at 06:13
  • @Eric: See the fourth comment of this answer. In it I admit that the solution is incorrect, but I left it dead-simple (yet @Robert edited it anyway) to demonstrate a basic principle - boxing is determined at compile time. The technically correct way to implement it is by calling it `IsUnboxed` and invert the `true`/`false` literals. But as the comment @Reb made above your first comment, he simply wanted to prevent users from sending reference types to his generic method. This can and should be done at compile time, and is the main point I was trying to make. – Allon Guralnek Apr 28 '11 at 08:08
  • 2
    I guess the real question is, is this variable on the Stack or the Heap? – Jodrell Apr 28 '11 at 08:48
  • @Eric - I don't have any problem with your analogy. I guess my point is that in the context of this question, if you want to know whether a value has been generated as the result of a boxing operation, when given a null value you cannot in general say whether it arose from boxing a nullable value or not. – kvb Apr 28 '11 at 12:27
  • What about `IEquatable e1 = 123; IsBoxed(e1);`? Shouldn't that succeed and return true rather than generating a compile-time error? – LukeH Apr 28 '11 at 13:54
  • I understand the rationale behind why "boxing" a null-valued nullable turns it into a null reference. However, an empty box is still a box. It just contains nothing. What we lose is the preservation of information. I would not expect Nullable to be treated by the runtime any differently than any other struct. It would be nice to say that when you unbox the boxed empty nullable it might be nice to know (sometimes) that it *would have* been a Nullable had it not been null. Perhaps I am wrong and it is provable that there is no information loss, or maybe it just doesn't matter. – James Dunne Apr 28 '11 at 14:43
  • 1
    That approach will not work if the passed-in variable is of a generic type which has neither a 'class' nor 'struct' constraint. – supercat Jan 13 '12 at 21:47
  • @JamesDunne: I really dislike the boxing behavior of `Nullable`; it provides as I see it exactly one advantage: `Object.Equals()` will report that a null-valued `Nullable` is equal to a null reference. I don't think that advantage is worth the cost (I would think one would usually know what things one was comparing, and could use appropriate methods, especially if there were a generic `INullable` interface with method `HasValue`) but perhaps there are some scenarios where it's really important. – supercat Feb 26 '12 at 20:25
  • 1
    This isn't an answer at all... The above code doesn't compile for the simplest of use cases (any class other than object as input will try to use the generic version and fail at compile time) and the _real_ answer is hidden in a lengthy trail of comments (littered with more or less irrelevant information not very helpful to the original question). **Comments Distilled: If you want to use value-types constrain your generics to `struct`**. (This will not include `string` and while it _probably_ matches the questions intent, it still doesn't answer the question as it is currently worded.) – AnorZaken Feb 23 '15 at 19:24
2

This approach is similar to Jared Par's answer. But I think !typeof(T).IsValueTypeis cleaner than enumerating all types which could contain a boxed value.

public static bool IsBoxed<T>(T value)
{
    return !typeof(T).IsValueType && (value != null) && value.GetType().IsValueType;
}

Unlike Jared's code this will handle the case where T is System.ValueType correctly.

Another subtle point is that value.GetType().IsValueType comes after !typeof(T).IsValueType since otherwise GetType() would create a temporary boxed copy of the value.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
2

If a type is a value type and its static type is 'dynamic' or 'object', or an interface, it is always boxed.

If a type is a value type and its static type is the actual type, it is never boxed.

Random832
  • 37,415
  • 3
  • 44
  • 63
2

Similar to Allon's answer, but should return the correct answer for any type without generating a compile-time error:

int i = 123;
Console.WriteLine(IsBoxed(i));    // false

object o = 123;
Console.WriteLine(IsBoxed(o));    // true

IComparable c = 123;
Console.WriteLine(IsBoxed(c));    // true

ValueType v = 123;
Console.WriteLine(IsBoxed(v));    // true

int? n1 = 123;
Console.WriteLine(IsBoxed(n1));    // false
int? n2 = null;
Console.WriteLine(IsBoxed(n2));    // false

string s1 = "foo";
Console.WriteLine(IsBoxed(s1));    // false
string s2 = null;
Console.WriteLine(IsBoxed(s2));    // false

// ...

public static bool IsBoxed<T>(T item)
{
    return (item != null) && (default(T) == null) && item.GetType().IsValueType;
}

public static bool IsBoxed<T>(T? item) where T : struct
{
    return false;
}

(Although you could make the argument that the possible compile-time error caused by Allon's code is a feature, not a bug: if you hit a compile-time error then you're definitely not dealing with an unboxed value type!)

Community
  • 1
  • 1
LukeH
  • 263,068
  • 57
  • 365
  • 409
1

I'm not sure if this will be relevant to anyone, but since I encountered this post because boxing was actually impacting my very dynamic mapping.

Sigil proivdes a fantastic UnBoxAny method

Assuming you have the following:

public class Report { public decimal Total { get; set; } }

new Dictionary<string, object> { { "Total", 5m} }

So the decimal value is boxed.

var totalProperty = typeof(Report).GetProperty("Total");

var value = emit.DeclareLocal<object>();

//invoke TryGetValue on dictionary to populate local 'value'*
                                                    //stack: [bool returned-TryGetValue]
//either Pop() or use in If/Else to consume value **
                                                    //stack: 
//load the Report instance to the top of the stack 
//(or create a new Report)
                                                    //stack: [report]
emit.LoadLocal(value);                              //stack: [report] [object value]
emit.UnboxAny(totalProperty.PropertyType);          //stack: [report] [decimal value]

//setter has signature "void (this Report, decimal)" 
//so it consumes two values off the stack and pushes nothing

emit.CallVirtual(totalProperty.SetMethod);          //stack: 

* invoke TryGetValue

** use in If/Else

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
1

I think actually the question is kind of misstated. Isn't the question actually, "How can I tell if an object is a box for another type?"

With reference to Allon's comment, if you have an object of type Object and the object is a primitive value type, it's a box. I'm not certain this is 100% correct, but (similar to Allon's implementation):

// Assume there is some object o.
bool isBoxed = o.GetType().IsPrimitive;
Kevin Hsu
  • 1,726
  • 11
  • 14
  • very helpful. I was using public void test(this T obj) { bool isPrimitive = typeof(T).IsPrimitive; } but, the results were incorrect on a boxed primitive – Devin Garner Mar 14 '12 at 14:10
-1

Try this:

    public static bool IsBoxed <T>(this T value) => 
       default(T) == null && value.GetType().IsValueType;
Majid Hajibaba
  • 3,105
  • 6
  • 23
  • 55
jgonte
  • 1
  • 2