13

I expect there's one of two answers to this, either impossible or extremely simple and I've overlooked the obvious Google query.

The underlying issue is that I have a generic object being passed in via an EventHandler that boxes the object and obfuscates the true type; only at runtime do I know what the object is.

Admittedly the dynamic keyword can get around the issue, but I'd like to not lose IntelliSense and everything if I can avoid it. Plus, it doesn't solve not knowing what each of the properties of the generic object are without massive amounts of reflection.

EDIT: The idea is to be able to determine the true type of the an object in a method parameter, and then cast that object as it's true type without knowing it in advance. This is but a simplified example. Boxed may have been the wrong term.

An example:

public class Program
{
    static void Main(string[] args)
    {
        var container = new Container<Containee>(
            new Containee
            {
                Property1 = Guid.NewGuid(),
                Property2 = "I'm a property!",
                Property3 = DateTime.Now
            }
        );

        var boxed = (object)container;

        var originalType = boxed.GetType();

        // DOES NOT COMPILE: would like an operation like this
        // EDIT: Request for more detail
        var actualType = boxed as originalType;
        actualType.Entity.Property2 = "But I like this better.";
    }
}

public class Containee
{
    public Guid Property1 { get; set; } 
    public string Property2 { get; set; }
    public DateTime Property3 { get; set; }
}

public class Container<T>
{
    public Container(T entity)
    {
        Entity = entity;
    }

    public T Entity { get; internal set; }
}

Clearly that won't compile, as there's not really a way to cast as a variable. However, I'm hoping there's a way to get a reference to the actual object and type, or at least, a way to dynamically re-create the type.

I expect there's something simple I'm overlooking, or a better way to get around it in general. The point is to be able to wrap any object in the container, and figure out later what it was.

falquan
  • 597
  • 4
  • 6
  • 11
  • 2
    I don't see any boxing in your code. You need to do `var actualType = boxed as Container;` to make it compilable. ` – Alex Aza Jun 10 '11 at 01:33
  • 4
    Boxing of classes do not happen. Only value types (int, etc) are boxed. The word you are looking for is `casting`. You have casted boxed to object. – Richard Schneider Jun 10 '11 at 01:36
  • I think the code sample is getting in the way. He mentions an event handler, so think of it as receiving `object sender`. He wants to know if there is any way at compile time to get the real type back and enjoy the benefits of intellisense. – Anthony Pegram Jun 10 '11 at 01:42
  • @Alex: That is not boxing. @Richard is correct; boxing is creating a referenced wrapper so that a value type can be stored on the heap. – Adam Robinson Jun 10 '11 at 01:42
  • I don't think you're coming across clearly. You say you don't want to "lose IntelliSense and everything", but if you don't know the type of the variable at the time you're writing the code, what does intellisense give you? You can't cast an object to an unknown type, as it would have no practical effect. – Adam Robinson Jun 10 '11 at 01:44

5 Answers5

9

The idea is to be able to determine the true type of the an object in a method parameter

That's easy enough (and you're already doing it).

Type actualType = param.GetType();

That will get you the actual concrete type of the object

and then cast that object as it's true type

This is where things come off the rails a bit. The casting operator in C# (usage of which is what people refer to as "casting") can do two things:

  1. Use type-specific explicit conversions to create a new object by applying the conversion to the existing object (note that this is a new reference that is created; the original object's type is never changed)
  2. Allow the developer to reference an object as a type that is at a different level in its inheritance hierarchy than is currently provided (or an interface that is implemented on a type that is lower in the hierarchy than is currently referenced)

In your case, the first option is right out; the casting operator, like all operators, is not polymorphic. That is, an operator is only applied if it is defined on the type that is being referenced, not the object that's being referenced. If you'd like further clarification on this, let me know, but I don't think it's germane to your question so I'm not going to go into it further unless asked.

The second option is the only option that could realistically apply to you, but consider the only two reasons you would want to do this:

  1. So that you can refer to the object as a specific concrete type that is at a lower level than is currently provided (in your case, your object is an object, so that's pretty much as high as it goes)
  2. So that you can refer to an object as a type that is higher in the hierarchy so that you can bypass hidden (but not overridden) members.

(The vast majority of casts are for reason #1)

The reason you would want to use either of those options is so that you can have a strongly-typed object and use the various members defined on that type. But all of these things only apply to types that you know when you're writing the code. It doesn't make sense to cast to a type that is unknown at compile time, as casting doesn't do anything to the actual object (it is, and shall remain, its true type; the only thing that changes is the type of the variable by which you reference the object).

If you can provide a further fleshed-out example of what you're actually trying to do (complete with code as you'd either like or expect it to work), I might be able to provide something modeled a little closer to what you want, but as it's described this is as specific as I can get.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • in practise that isn't what GetType does. ended up finding this in google searches because GetType is returning "ListViewItem" but when i look at said item in the debugger it says "CustomListViewItem" – KittyDotNet Jun 27 '22 at 21:00
4

First of all: That's not "boxing". Boxing is for value types, like structs.

Second of all: What you probably need is either:

  • Compile-time reflection, which C# doesn't have
  • Dynamic code generation, which you can do (painfully) with Reflection.Emit.

Third of all: Your sample code does variable1 as variable2, which doesn't really make sense. :\ What are you intending to do after that? Perhaps there's a better way.

Downvoter
  • 551
  • 4
  • 14
2

You could use dynamic:

dynamic actualType = boxed;
actualType.Entity.Property2 = "But I like this better.";

This should compile and work.

Alex Aza
  • 76,499
  • 26
  • 155
  • 134
1
var actualType = boxed as originalType;

Just so we're on the same page, let me explain why this is impossible.

var is a compile time construct. It is, identical to declaring the variable with the proper type straight off. Besides being easier to type, it's main use is for anonymous types which, as implied, have no names.

Anyway, to get to the meat of your question, your best bet is to use Dynamic code generation, either with Reflection.Emit or CodeDom (the latter is much easier to understand if you don't know ILASM, but is much slower).

Depending on what you actually want to do, you might be able to get away with something like

if(someObject is Container<Containee>) {
     var container = (Container<Containee>)someObject;
     //...
}

But, if you can expect literally any type, well... good luck.

Mike Caron
  • 14,351
  • 4
  • 49
  • 77
  • While your points about why casting a variable to a variable is impossible are obviously correct, I think the latter part of the post (the meat, in other words) is premature; the OP is not clear on what he wants to *do*, so I'm not sure anyone is in a position to offer suggestions about how to do it yet ;) – Adam Robinson Jun 10 '11 at 01:47
  • 1
    @Adam, `Depending on what you actually want to do` I included that for a reason ;) – Mike Caron Jun 10 '11 at 01:51
1

The underlying issue is that I have a generic object being passed in via an EventHandler that boxes the object and obfuscates the true type; only at runtime do I know what the object is.

How do you want to handle it, if the type is only known at runtime? You can't call any specific class methods because you won't know the exact type anyway, unless all objects share some set of methods which can be extracted as interface.

Basically, you have several options:

  • Use is and do different things for different types:

    object value = GetValue ();
    if (value is Program)
        ((Program)value).Run ();
    else if (value is Animal)
        ((Animal)value).Run ();
    
  • If all possible types are supposed to share a set of operations, use an interface:

    object value = GetValue ();
    IRunnable runnable = (IRunnable)value;
    runnable.Run ();
    
  • Rephrase your question and extend your sample with how you see it working after you've done the ‘magical casting’. This would give us the idea what you're trying to accomplish.

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511