将盒装对象转换回原始类型

时间:2011-06-10 01:30:19

标签: c# generics reflection event-handling boxing

我希望有两个答案中的一个,要么不可能,要么非常简单,我忽略了明显的Google查询。

潜在的问题是我有一个通用对象通过EventHandler传入,该对象将对象装箱并模糊真实类型;只有在运行时我才知道对象是什么。

不可否认,dynamic关键字可以解决问题,但我希望不会丢失IntelliSense以及所有内容,如果我可以避免它。另外,如果没有大量反射,它无法解决不知道通用对象的每个属性的问题。

编辑:我们的想法是能够确定方法参数中对象的真实类型,然后在不事先知道的情况下将该对象转换为真实类型。这只是一个简化的例子。盒装可能是错误的术语。

一个例子:

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; }
}

显然,这不会编译,因为没有真正的方法可以作为变量进行转换。但是,我希望有一种方法可以获得对实际对象和类型的引用,或者至少是一种动态重新创建类型的方法。

我希望有一些简单的东西我可以忽略,或者更好的解决方法。关键是能够将任何对象包装在容器中,并稍后弄清楚它是什么。

5 个答案:

答案 0 :(得分:8)

  

我们的想法是能够确定方法参数

中对象的真实类型

这很容易(你已经在做了)。

Type actualType = param.GetType();

这将为您提供对象的实际具体类型

  

然后将该对象转换为真正的类型

这是事情发生的地方。 C#中的转换操作符(其用法是人们称之为“转换”)可以做两件事:

  1. 使用特定于类型的显式转换通过将转换应用于现有对象来创建新对象(请注意,这是创建的 new 引用;原始对象的类型永远不会更改)< / LI>
  2. 允许开发人员将对象引用为其继承层次结构中与当前提供的类型不同的类型(或者在层次结构中比当前引用的类型更低的类型上实现的接口)
  3. 在您的情况下,第一个选项是正确的;与所有运算符一样,转换运算符不是多态的。也就是说,只有在被引用的类型上定义了运算符,而不是被引用的对象时才应用运算符。如果您想进一步澄清这一点,请告诉我,但我不认为这与您的问题密切相关,所以除非被问到,否则我不打算进一步澄清。

    第二个选项是唯一可以实际应用于您的选项,但请考虑您希望执行此操作的唯一两个原因:

    1. 因此,您可以将对象称为特定的具体类型,其级别低于当前提供的级别(在您的情况下,您的对象是object,因此它几乎与它一样高)
    2. 这样您就可以将对象引用为层次结构中 higher 的类型,以便绕过隐藏(但不会被覆盖)的成员。
    3. (绝大多数演员出于理由#1)

      您希望使用其中任何一个选项的原因是,您可以拥有强类型对象并使用在该类型上定义的各种成员。但是,所有这些内容仅适用于您在编写代码时知道的类型。强制转换为在编译时未知的类型是没有意义的,因为强制转换对实际对象没有任何作用(它是,并且将保留,它的真实类型;唯一改变的是类型用于引用对象的变量

      如果您可以提供一个进一步充实的示例,说明您实际上要做什么(完成代码,或者您希望或希望它能够工作),我可能能够提供更接近模仿的东西你想要什么,但正如我所描述的那样,这是我能得到的具体内容。

答案 1 :(得分:4)

首先:那不是“拳击”。拳击用于值类型,例如struct s。

其次:您可能需要的是:

  • 编译时反射,C#没有
  • 动态代码生成,您可以{痛苦地]使用Reflection.Emit

第三点:您的示例代码确实variable1 as variable2,这实际上没有意义。 :\那你打算做什么?也许还有更好的方法。

答案 2 :(得分:1)

var actualType = boxed as originalType;

正好我们在同一页上,让我解释为什么这是不可能的。

var是一个编译时构造。它与直接声明具有正确类型的变量相同。除了更容易键入外,它主要用于匿名类型,如暗示的那样,没有名称。

无论如何,为了解决您的问题,最好的办法是使用动态代码生成,Reflection.EmitCodeDom(如果不这样做,后者会更容易理解知道ILASM,但要慢得多。)

根据你真正想做的事情,你可能会躲过像

这样的事情
if(someObject is Container<Containee>) {
     var container = (Container<Containee>)someObject;
     //...
}

但是,如果你可以期待任何类型,那么......祝你好运。

答案 3 :(得分:1)

  

潜在的问题是我有一个   通过一个传入的通用对象   包装对象的EventHandler和   混淆真实的类型;只在   运行时我知道对象是什么。

如果仅在运行时知道类型,您希望如何处理它?您不能调用任何特定的类方法,因为您无论如何都不会知道确切的类型,除非所有对象共享一组可以作为接口提取的方法。

基本上,您有几种选择:

  • 使用is并针对不同类型执行不同的操作:

    object value = GetValue ();
    if (value is Program)
        ((Program)value).Run ();
    else if (value is Animal)
        ((Animal)value).Run ();
    
  • 如果所有可能的类型都应该共享一组操作,请使用接口:

    object value = GetValue ();
    IRunnable runnable = (IRunnable)value;
    runnable.Run ();
    
  • 改写您的问题,并在完成'魔法铸造'之后,将您的样本扩展为您的工作方式。这会让我们知道你想要完成的任务。

答案 4 :(得分:1)

您可以使用dynamic

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

这应该编译和工作。