Это просто демонстрация.Не используйте его в производстве.
Вы просите что-то неестественное для c #.И мне нравится это.Приготовьтесь посмотреть немного магии.Но давайте начнем с исправления исходного кода.Во-первых, давайте изменим имя основного класса на производноеТакже известно, что встроенная инициализация поля является синтаксическим сахаром.Компилятор устанавливает инициализацию для всех конструкторов.Мы тоже.И давайте добавим нулевое слияние.Поначалу это не повлияет на результат, но поможет в дальнейшем.И мы также должны поместить наши классы в отдельную библиотеку классов (например, ClassLibrary).Итак, у нас есть:
namespace ClassLibrary
{
public class Base
{
public string myString;
public Base(string str)
{
myString = myString ?? "Hi";
myString += str;
}
}
public class Derived : Base
{
public Derived() : base(" world")
{
base.myString = "Hello";
}
}
}
Затем скомпилируйте библиотеку, создайте консольное приложение и добавьте ссылку на скомпилированную dll с помощью Добавить ссылку ... -> Обзор -> Обзор ... Добавить код, подобный вашему:
using System;
using ClassLibrary;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Derived().myString);
}
}
}
Вывод просто Hello
, как в вашем случае.
Теперь откройте dll с помощью ildasm и сбросьте его (File -> Dump, Dump IL Code проверено) в ClassLibrary.иль и выход ildasm.Откройте ClassLibrary.il в любом текстовом редакторе и найдите конструктор производного класса.Он начинается с .class public auto ansi beforefieldinit ClassLibrary.Derived
и содержит:
IL_0000: ldarg.0
IL_0001: ldstr " world"
IL_0006: call instance void ClassLibrary.Base::.ctor(string)
IL_000b: nop
IL_000c: nop
IL_000d: ldarg.0
IL_000e: ldstr "Hello"
IL_0013: stfld string ClassLibrary.Base::myString
IL_0018: ret
Измените его на (в IL вызывается конструктор базового класса в любом месте вручную):
IL_0000: ldarg.0
IL_0001: ldstr "Hello"
IL_0006: stfld string ClassLibrary.Base::myString
IL_000b: nop
IL_000c: nop
IL_000d: ldarg.0
IL_000e: ldstr " world"
IL_0013: call instance void ClassLibrary.Base::.ctor(string)
IL_0018: ret
Затем сохраните ClassLibrary.il и из командызапрос на запуск:
"%ILASM_LOCATION%\ilasm.exe" "%ClassLibrary.il_LOCATION%\ClassLibrary.il" /dll /output:"%ClassLibrary.dll_LOCATION%\ClassLibrary.dll"
Запустите консольное приложение еще раз и посмотрите: Hello world
Открыт с помощью ILSpy Производные классы выглядят:
public class Derived : Base
{
public Derived()
{
myString = "Hello";
base..ctor(" world");
}
}
Но помещены в проект ClassLibraryон дает:
Ошибка CS1001 Ожидается идентификатор ...
Ошибка CS7036 Не указан аргумент, который соответствует необходимому формальному параметру 'str' из Base.Base (строка)'...
Ошибка CS0117 «База» не содержит определения для «» ...
Обновление :
Магияотражения:
using System;
using System.Reflection;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Derived().myString);
}
}
public static class TraceHelper
{
public static void Trace(string message)
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Trace: {message}.");
Console.ForegroundColor = color;
}
}
public class Base
{
public string myString;
public Base(string str)
{
TraceHelper.Trace("Base constructor called");
myString = myString ?? "Hi";
myString += str;
}
}
public class Derived : Base
{
private static readonly ConstructorInfo baseCtor = typeof(Base).GetConstructor(new[] { typeof(string) });
public Derived() : base(null)
{
TraceHelper.Trace("Derived constructor called");
base.myString = "Hello";
@base(" world");
}
private void @base(string str)
{
baseCtor.Invoke(this, new[] { str });
}
}
}
Вывод:
Trace: Base constructor called.
Trace: Derived constructor called.
Trace: Base constructor called.
Hello world
Результат "Hello world" , но базовый конструктор вызывается дважды .