Как стать автором
Обновить

Комментарии 43

class App { static App() {/* код до Main */} static void Main() {}}

Это то, что сразу пришло в голову.
да, этот способ годится + есть много его вариаций )
может, еще какой-то знаете?
Больше никакого не знаю, в том плане, что никогда не задумывался над вопросом, как можно выполнить функцию до Main().

С другой стороны, возможностей должно быть достаточно много. Если покопаться — можно попробовать найти те вещи, которая инфраструктура .NET так или иначе запускает до Main() и привязаться к ним. Но это надо смотреть, чем я сейчас и занимаюсь.
так?
using System;

class Y
{
 public Y()
 {
  Console.Write("0");
 }
}

class X
{
 private X(string s)
 {
  Console.Write(s);
 }

 public X() : this("_")
 {
  Console.Write("o");
 }
 Y y = new Y();
}

class App
{
 static void Main()
 {
  X x = new X();
 }
}


* This source code was highlighted with Source Code Highlighter.
Или так?
using System;

class Y
{
 public Y()
 {
  Console.Write("0");
 }
}

class Z
{
 public Z()
 {
  Console.Write("_");
 }
}

class X : Z
{
 public X()
 {
  Console.Write("o");
 }
 Y y = new Y();
}

class App
{
 static void Main()
 {
  X x = new X();
 }
}


* This source code was highlighted with Source Code Highlighter.
этот вариант правильный, предыдущий — нет, поскольку меняет код конструктора X.X
кстати технически наследование тоже меняет код конструктора — в IL между инициализаторами полей и телом конструктора вставится вызов конструктора базового класса.
спасибо за ремарку, но под кодом в данном случае (и всех остальных) я подразумеваю исключительно C#-код, если не сказано обратное
:this("_") — это вызов конструктора, в принципе равноценно изменению кода метода. Насколько я понял, по условию это не допустимо.
да, согласен. потому и написал второй вариант.
А инициализацию Y можно менять? На Y y = new Y("");?
по условию — нельзя
В общем, у меня случился такой код. Он работает и решает именно эту задачу.

using System;
using System.Threading;
using System.IO;

class Y
{
  public Y()
  {
    Console.Write("0");
  }
}

class X
{
  public X()
  {
    Console.Write("o");
  }
  Y y = new Y();
}

class App
{
  public class CustomWriter : TextWriter
  {
    private TextWriter c = null;

    public CustomWriter()
    {
      c = Console.Out;
      Console.SetOut(this);
    }

    public override System.Text.Encoding Encoding
    {
      get { return c.Encoding; }
    }

    public override void Write(object value)
    {
      c.Write(value);
    }

    public override void Write(string value)
    {
      c.Write(value);
      if (value == "0")
        c.Write("_");
    }
  }

  static App()
  {
    Console.SetOut(new CustomWriter());
  }

  static void Main()
  {
    X x = new X();
    Console.ReadLine();
  }
}


* This source code was highlighted with Source Code Highlighter.

да, можно принять как правильное ))
похоже, я недостаточно наложил ограничений на консольный вывод )
Да, надо было еще накладывать ограничение на недопустимость перенаправления стандартных потоков ввода-вывода, тогда этот код стал бы невозможен.

Но, в принципе, тут смотря что от задачи требуется. Мой код решает задачу, даже если накладывается ограничение на полную неизменность классов X и Y.
Вы и так уже наложили столько ограничений, что задачка определенно напоминает сферического коня в вакууме. кажется, вам просто пришел в голову некий вариант, а дальше вы усиленно пытаетесь всех к нему склонить, загоняя ограничениями в прокрустово ложе, хотя в таких задачах самое интересное обычно — неожиданный подход, как в посте выше. Примерно так же работают некоторые учителя в школах(и не только в школах), к сожалению.
насчет сферического коня спорить не буду )
а смысл в такой задачке был в порядке вызова элементов — инициализатор производного типа, конструктор базового типа, конструктор производного типа. мне эта последовательность показалась неочевидной, на ней я и попытался построить задачку. то, что bobermaniac смог мои ограничения обойти — ему только в плюс, я считаю
Добавляем в конец
class MyApp
{
static void Main()
{
Console.Write(«0_o»);
}
}

и компилим с опцией /main:MyApp
первое ограничение запрещает определять еще один метод Main ;)
Проглядел :(
А можно мне тоже какой-нибудь «этюд» запостить?
буду только рад!
А, кстати, о вызове когда до Main не поведаете?

Еще будет замечательно, если поведаете, как вы это обнаружили и когда такие вызовы бывают нужны.
вот ниже показали еще способ
ну и применим тот же способ, которым решается этюд
по сути в этом и заключался исходный этюд для канала #c# )
Ну такой вызов — это дурной тон. Код в конструкторе, да еще и эксепшн если вылетит, перехватить его не удастся. Жуть.
да, пожалуй
кстати, какого типа будет это неперехваченное исключение? )
TargetInvocationException, как и любое другое исключение, выкинутое из конструктора.
MSDN говорит о TargetInvocationException: The exception that is thrown by methods invoked through reflection

Здесь у нас нет рефлексии вроде бы. Давайте сформулирую четче: речь идет о коде habrahabr.ru/blogs/net/77039/#comment_2241555
какое исключение получится в результате, если конструктор Z.Z() бросит, скажем, NullReferenceException?
В таком случае NullReferenceException и вылетит.
нет )
NullReferenceException будет обернут внутрь другого исключения
убедитесь сами
Эмм…

class Test
{
  public Test() { throw new ApplicationException(); }
}

class App
{
  static void Main()
  {
    try
    {
      new Test();
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.GetType().FullName);
    }
    Console.ReadLine();
  }
}


* This source code was highlighted with Source Code Highlighter.


Выдает System.ApplicationException с полным стеком. Аналогично для NullReferenceException.
Ваш код радикально отличается от того, что приведен ниже )
смысл в том, что передаваемый там эксепшн нельзя перехватить обычными средствами, и приходится смотреть вывод консоли:
class Test
{
 static Test() { throw new ApplicationException(); }
}

class App
{
 static void Main()
 {
   Test test = new Test();
 }
}


* This source code was highlighted with Source Code Highlighter.

обратите внимание на то, что конструктор статический
других, к сожалению, не знаю, но очень хочется узнать
кстати, есть еще один способ — через атрибуты. правда, в мелкософте об этом догадались, и все атрибуты, которые проверяются перед запуском, помечены как sealed (
так что только через подмену сборки со стандартными атрибутами
Вот так вызовется до Main. Правда вставить "_" между Oо не получается пока.
class App
{
public static Z z = new Z();
static void Main()
{
X x = new X();
}
}
class App
{
[AutoStart()]
static void Main()
{
}
}

public class AutoStartAttribute: Attribute
{
public AutoStartAttribute()
{
Console.Beep();
}
}
у меня не срабатывает, фреймворк 3.5 SP1
смотрите habrahabr.ru/blogs/net/77039/#comment_2241758
пользовательские атрибуты создаются, когда их запрашивают
можно было бы унаследовать атрибут, который запрашивает сама среда выполнения (InAttribute, STAThreadAttribute), но, похоже, все они sealed
Кхм, а у меня срабатывает, тоже SP1 3.5. По стеку видно, что internal код вызывает GetCustomAttributes… ну и в результате логичное создание экземпляра нашего атрибута
любопытно.
покажите тогда полностью код и параметры компилятора
у Вас один файл на вход компилятору подается?
параметры дефолтные… я просто создал новый консольный проект

v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\ConsoleApplication2.exe /target:exe Program.cs Properties\AssemblyInfo.cs
ага, воспроизвел
такое поведение получается в случае, если пускать проект из-под студии по F5 (в режиме отладки). Попробуйте запустить в обычном режиме (Ctrl + F5), либо прямо из папки bin
я свои примеры кода компилирую обычно из командной строки, потому не сразу понял, в чем дело
Ещё одно решение. Только если вставить Console.ReadLine() в Main, то работать не будет. Запускать нагляднее не из VS а из коммандной строки.
class Y {
    public Y() {
      Console.Write("0");
    }
  }

  class X {
    public X() {
      Console.Write("o");
    }
    Y y = new Y();
  }

  class Z {
    ~Z() {
      Console.Write("\r0_o");
    }
  }

  class App {
    static void Main() {
      X x = new X();
    }

    static Z z = new Z();
  }


* This source code was highlighted with Source Code Highlighter.
да, тоже работает
все-таки ограничения стимулируют фантазию )
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации