Как вы можете наследовать от закрытого класса, используя отражение в .Net?

Прежде чем начать стрелять в меня, я НЕ собираюсь это делать, но кто-то из другого сообщения сказал, что это возможно. Как это возможно? Я никогда не слышал о наследовании от чего-либо, используя отражение. Но я видел некоторые странные вещи...

Ответы

Ответ 1

Без переопределения виртуальных функций в подклассе закрытого класса не так много.

Если вы попытаетесь записать закрытый класс с виртуальной функцией в нем, вы получите следующую ошибку компилятора:

// 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 на самом деле ее применяет. Вам придется загрузить код, разобрать его, удалить "загерметизированный" бит, затем собрать его и загрузить новую версию.

Ответ 2

Прошу прощения за размещение неверных предположений в другом потоке, я не смог правильно запомнить. Используя следующий пример, используя 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();
   }
}

Ответ 3

Он МОЖЕТ (увеличил бы размер, если бы мог). Согласно ребятам на freenode, это включало бы изменение байтового кода с использованием Reflection.Emit и передачу JIT нового набора байтового кода.

Не то, чтобы я KNOW, как... это было именно то, что они думали.

Ответ 4

Другой плакат, возможно, больше думал о линиях Reflection.Emit, а не о более обычных API Reflection для чтения.

Однако все еще невозможно (по крайней мере, согласно в этой статье). Но, безусловно, можно открутить что-то с Reflection.Emit, которые не попали в ловушку, пока вы не попытаетесь фактически выполнить испущенный код.

Ответ 5

Создайте новый класс GenericKeyValueBase

поместите это в него

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

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

И наследуйте от этого плюс вы можете добавить дополнительные методы расширения для Add/Remove (AddAt и RemoveAt) к вашему новому производному классу (и сделать его сборником/словарем), если вы чувствуете себя действительно круто.

Простой пример внедрения, в котором вы бы использовали обычный System.Collections.Generic.KeyValuePair для базы, но вместо этого можете использовать приведенный выше код

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