Как вы можете наследовать от запечатанного класса, используя отражение в .Net? - PullRequest
18 голосов
/ 01 октября 2008

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

Ответы [ 5 ]

14 голосов
/ 01 октября 2008

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

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

// 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 (ruby - самый хакерский из всех хакерских языков), но даже он не позволил мне.

«Запечатанная» часть встроена в MSIL, поэтому я предполагаю, что сам CLR фактически обеспечивает это. Вам нужно будет загрузить код, разобрать его, удалить запечатанный бит, затем снова собрать и загрузить новую версию.

9 голосов
/ 01 октября 2008

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

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

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

1 голос
/ 01 октября 2008

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

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

0 голосов
/ 02 июня 2009

Создайте новый класс с именем 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)
        {
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...