Как вы можете наследовать от закрытого класса, используя отражение в .Net?
-
03-07-2019 - |
Вопрос
Прежде чем вы начнете стрелять в меня, я НЕ собираюсь этого делать, но кое-кто в еще одно сообщение сказал, что это возможно.Как это возможно?Я никогда не слышал о наследовании от чего-либо с помощью отражения.Но я видел кое-какие странные вещи...
Решение
Без переопределяемых виртуальных функций нет особого смысла создавать подклассы для закрытого класса.
Если вы попытаетесь написать закрытый класс с виртуальной функцией в нем, вы получите следующую ошибку компилятора:
// 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 фактически обеспечивает это.Вам пришлось бы загрузить код, разобрать его, удалить "запечатанный" бит, затем собрать его заново и загрузить новую версию.
Другие советы
Я прошу прощения за публикацию неверных предположений в другой теме, я не смог правильно вспомнить.Используя следующий пример, используя отражение.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();
}
}
IT МОГ БЫ (увеличил бы размер, если бы мог).По словам ребят из freenode, это потребовало бы изменения байтового кода с использованием Reflection.Emit и передачи JIT нового набора байтового кода.
Не то чтобы я ЗНАТЬ как ...это было именно то, что они думали.
Другой участник, возможно, больше думал о Рефлексии.Emit, а не о более обычных API-интерфейсах Reflection, доступных только для чтения.
Однако это по-прежнему невозможно (по крайней мере, в соответствии с эта статья).Но, безусловно, можно что-то испортить с отражением.Излучение, которое не попадает в ловушку, пока вы не попытаетесь фактически выполнить переданный код.
Создайте новый класс под названием 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) в свой новый производный класс (и сделать его коллекцией / словарем), если вам действительно нравится.
Простой пример внедрения, в котором вы могли бы использовать обычную систему.Коллекции.Generic.KeyValuePair для базы, но вместо этого можно использовать приведенный выше код
class GenericCookieItem<TCookieKey, TCookieValue> : GenericKeyValueBase<TCookieKey,TCookieValue>
{
public GenericCookieItem(TCookieKey KeyValue, TCookieValue ItemValue) : base(KeyValue, ItemValue)
{
}
}