Как вы можете наследовать от закрытого класса, используя отражение в .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)
{
}
}