如何在.Net中使用反射从密封的类继承?

时间:2020-03-06 14:56:53  来源:igfitidea点击:

在我们开始对我开除之前,我不打算这样做,但是另一篇文章中的某人说这是可能的。这怎么可能?我从未听说过使用反射从任何东西继承。但是我看到了一些奇怪的事情...

解决方案

可能(如果可以的话,会增加尺寸)。据freenode上的人说,这涉及到使用Reflection.Emit修改字节码,并为JIT传递一组新的字节码。

并不是我知道如何……这正是他们的想法。

另一位发布者可能一直在思考着更多的Reflection.Emit问题,而不是更常见的只读反射API。

但是,仍然不可能(至少根据本文而言)。但是肯定有可能用Reflection.Emit解决这些问题,直到我们尝试实际执行所发出的代码为止。

如果没有要重写的虚函数,则对密封类进行子类化就没有多大意义。

如果尝试编写其中包含虚拟函数的密封类,则会出现以下编译器错误:

// error CS0549: 'Seal.GetName()' is a new virtual member in sealed class 'Seal'

但是,我们可以通过在基类中声明虚函数,从而将虚函数放入密封类中,如下所示:

public abstract class Animal
{
    private readonly string m_name;

    public virtual string GetName() { return m_name; }

    public Animal( string name )
    { m_name = name; }
}

public sealed class Seal : Animal
{
    public Seal( string name ) : base(name) {}
}

但是问题仍然存在,我看不到如何偷偷通过编译器来声明子类。我尝试使用IronRuby(红宝石是所有杂乱无章的语言中最烂的一种),但即使这样也不允许我这样做。

"密封"部分嵌入到MSIL中,因此我猜想CLR本身实际上是在强制执行此操作。我们必须加载代码,将其反汇编,删除"密封"位,然后重新组装,并加载新版本。

我很抱歉在另一个线程中发布了错误的假设,但未能正确回忆。使用下面的示例,使用Reflection.Emit,展示了如何从另一个类派生,但是在运行时抛出TypeLoadException失败。

sealed class Sealed
{
   public int x;
   public int y;
}

class Program
{
   static void Main(string[] args)
   {
      AppDomain ad = Thread.GetDomain();
      AssemblyName an = new AssemblyName();
      an.Name = "MyAssembly";
      AssemblyBuilder ab = ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
      ModuleBuilder mb = ab.DefineDynamicModule("MyModule");
      TypeBuilder tb = mb.DefineType("MyType", TypeAttributes.Class, typeof(Sealed));

      // Following throws TypeLoadException: Could not load type 'MyType' from
      // assembly 'MyAssembly' because the parent type is sealed.
      Type t = tb.CreateType();
   }
}

创建一个名为GenericKeyValueBase的新类

把它放进去

public class GenericKeyValueBase<TKey,TValue>
    {
        public TKey Key;
        public TValue Value;

        public GenericKeyValueBase(TKey ItemKey, TValue ItemValue)
        {
            Key = ItemKey;
            Value = ItemValue;
        }
    }

并从该继承中继承,如果我们真的很酷,则可以将添加/删除的其他扩展方法(AddAt和RemoveAt)添加到新的派生类(并使其成为集合/词典)。

一个简单的示例示例,在该示例中,我们将使用普通的System.Collections.Generic.KeyValuePair作为基础,但可以使用上面的代码

class GenericCookieItem<TCookieKey, TCookieValue> : GenericKeyValueBase<TCookieKey,TCookieValue>
    {
        public GenericCookieItem(TCookieKey KeyValue, TCookieValue ItemValue) : base(KeyValue, ItemValue)
        {
        }
    }