Re[11]: Стоит ли переносить инициализацию в отдельный метод?
От: abibok  
Дата: 03.07.13 18:05
Оценка:
A>Это что-то фирменное. Можно показать?

Это очень круто в плане debuggability, позволяет избавиться от необходимости постоянно логировать всякие мелочи, работает прозрачно для существующего и нового кода.
Показать не могу.
Re[12]: Стоит ли переносить инициализацию в отдельный метод?
От: artelk  
Дата: 03.07.13 18:11
Оценка:
Здравствуйте, abibok, Вы писали:

A>>Это что-то фирменное. Можно показать?


A>Это очень круто в плане debuggability, позволяет избавиться от необходимости постоянно логировать всякие мелочи, работает прозрачно для существующего и нового кода.

A>Показать не могу.

hackability?
Забавно, что в качестве аргумента ты используешь то, что показать не можешь...
Re[13]: Стоит ли переносить инициализацию в отдельный метод?
От: abibok  
Дата: 03.07.13 18:21
Оценка:
A>hackability?

В том числе, когда это касается воровства контекста повышенных привилегий. Вызываем мы "некоторый" метод как юзер, а он внутри делает

public void Foo(Something x)
try
{
    GiveMeAdminPrivileges();
    Process(x);
}
finally
{
    RevertToUserPrivileges();
}


и думает, что все безопасно, привилегии не уйдут вызывающему. А мы подсунем такой x, который приведет к исключению, и перехватим его до входа в finally, и вернемся в свой код ненадого.

A>Забавно, что в качестве аргумента ты используешь то, что показать не можешь...


В качестве аргумента я описываю реальную задачу, пусть и не очень распространенную (что нормально для всякой достаточно сложной задачи), а вот реализацию показать не могу. Но это не отменяет существование задачи и проблемы.
Re[14]: Стоит ли переносить инициализацию в отдельный метод?
От: artelk  
Дата: 03.07.13 19:48
Оценка:
Здравствуйте, abibok, Вы писали:

A>>hackability?


A>В том числе, когда это касается воровства контекста повышенных привилегий. Вызываем мы "некоторый" метод как юзер, а он внутри делает


A>
A>public void Foo(Something x)
A>try
A>{
A>    GiveMeAdminPrivileges();
A>    Process(x);
A>}
A>finally
A>{
A>    RevertToUserPrivileges();
A>}
A>


A>и думает, что все безопасно, привилегии не уйдут вызывающему. А мы подсунем такой x, который приведет к исключению, и перехватим его до входа в finally, и вернемся в свой код ненадого.

Интересно. А если Foo лежит в подписанной сборке в GAC, тоже перехватите? А Code Access Security тоже умеете обходить?

A>>Забавно, что в качестве аргумента ты используешь то, что показать не можешь...

A>В качестве аргумента я описываю реальную задачу, пусть и не очень распространенную (что нормально для всякой достаточно сложной задачи), а вот реализацию показать не могу. Но это не отменяет существование задачи и проблемы.
Описание задачи и ее существование не может быть аргументом.
Re[15]: Стоит ли переносить инициализацию в отдельный метод?
От: abibok  
Дата: 03.07.13 20:38
Оценка:
A>Интересно. А если Foo лежит в подписанной сборке в GAC, тоже перехватите? А Code Access Security тоже умеете обходить?

Дайте пример кода, я попробую, чтобы не гадать. Подпись не должна влиять, мы не изменяем сборку.
Re[3]: UninitializedException
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.07.13 04:23
Оценка: 4 (1) +2
Здравствуйте, drol, Вы писали:
D>Это верно только для однопоточной ситуации. В многопоточном случае возможны такие "чудеса", как выполнение конструктора параллельно с финализатором.
Чтобы финализатор начал выполняться параллельно с конструктором, нужно, чтобы поток исполнения конструктора дошёл до места, после которого нет обращений к this.
Это означает, что если у нас есть недоинициализированный экземпляр, то ссылка на него удерживается в рутах GC, и в лапы финализатора он не попадёт.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Хороший вопрос
От: Sinix  
Дата: 04.07.13 06:54
Оценка:
Здравствуйте, drol, Вы писали:


D>Кэш данных в архитектурах x86/x64 когерентен. И к обсуждаемым вопросам не имеет никакого отношения.


Не для холивара

Ок, а чем ещё можно объяснить, что пример igor-booch (чуть допилил) не падает?
    class Program
    {
        static Foo foo = new Foo(10000);
        static void Main(string[] args)
        {
            Thread instantiationThread = new Thread(() =>
            {
                do
                {
                    foo = new Foo(10000);
                } while (true);
            });

            Thread checkInitializedThread = new Thread(() =>
            {
                do
                {
                    var local = foo;
                    if (!local._initialized1 | !local._initialized2 | local._val == 0)
                    {
                        Console.WriteLine("Bingo!!!");
                    }
                } while (true);
            });

            instantiationThread.Start();
            checkInitializedThread.Start();
            Console.ReadKey();
        }
        
        class Foo
        {
            private static readonly Random rnd = new Random(0);

            public bool _initialized1;
            public bool _initialized2;
            public int _val;


            public Foo(int count)
            {
                //Thread.Sleep(10);
                _initialized1 = true;
                //Thread.Sleep(10);
                _initialized2 = true;

                _val = rnd.Next(count) + 1;
            }
        }
    }



В дизасме никакой магии нет.
  Скрытый текст
                    foo = new Foo(10000); (конструктор заинлайнен)
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        esi  
00000004  mov         ecx,193488h 
00000009  call        FFCE1E14 
0000000e  mov         esi,eax 
00000010  mov         byte ptr [esi+8],1 
00000014  mov         byte ptr [esi+9],1 
00000018  mov         ecx,dword ptr ds:[035E1F0Ch] 
0000001e  mov         edx,2710h 
00000023  mov         eax,dword ptr [ecx] 
00000025  call        dword ptr [eax+44h] 
00000028  inc         eax  
00000029  mov         dword ptr [esi+4],eax
0000002c  lea         edx,ds:[035E1F00h] 
00000032  call        72232DD0 
00000037  jmp         00000004


                    var local = foo;
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  mov         ecx,dword ptr ds:[035E1F00h]
Re[4]: UninitializedException
От: drol  
Дата: 04.07.13 07:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Чтобы финализатор начал выполняться параллельно с конструктором, нужно, чтобы поток исполнения конструктора дошёл до места, после которого нет обращений к this.


Ну да. В чём проблема-то ?

S>Это означает, что если у нас есть недоинициализированный экземпляр, то ссылка на него удерживается в рутах GC, и в лапы финализатора он не попадёт.


Ты как-то узко понимаешь инициализацию. Вот есть поле. Конструктор проставил в него ссылку на объект. А теперь вызывает какие-то методы этого объекта. С этого момента зависимости по this уже нет. Однако инициализация идёт во всю.
Re[15]: Стоит ли переносить инициализацию в отдельный метод?
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.07.13 07:28
Оценка:
Здравствуйте, artelk, Вы писали:

A>>и думает, что все безопасно, привилегии не уйдут вызывающему. А мы подсунем такой x, который приведет к исключению, и перехватим его до входа в finally, и вернемся в свой код ненадого.

A>Интересно. А если Foo лежит в подписанной сборке в GAC, тоже перехватите? А Code Access Security тоже умеете обходить?
Ну конечно же да. Они же явно пользуются Debugger Services и шаманством с CLR Host, а там all bets are off.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Хороший вопрос
От: drol  
Дата: 04.07.13 07:52
Оценка: 20 (1)
Здравствуйте, Sinix, Вы писали:

S>Ок, а чем ещё можно объяснить, что пример igor-booch (чуть допилил) не падает?


Тем, что JIT у CLR очень недалёкий. Видно же в ассемблере, что чтение ссылки из памяти происходит на каждой итерации. Замените потроха checkInitializedThread на более простую конструкцию:

var local = foo;
do
{
} while (local==foo);

Console.WriteLine("local != foo");


...и всё сразу станет по-другому (при запуске Release-сборки вне Visual Studio).
Re[2]: Стоит ли переносить инициализацию в отдельный метод?
От: icWasya  
Дата: 04.07.13 09:01
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Аноним, Вы писали:


А>>Есть ли у этого подхода преимущества перед обычной инициализацией через конструктор в C#?

HL>Что имеется ввиду? Это:
HL>
HL>class MyClass
HL>{
HL>    private MyClass()
HL>    {
HL>    }    

HL>    public MyClass Create(){};
HL>}
HL>

HL>это:
HL>
HL>class MyClass()
HL>{
HL>    private void Initialize()
HL>    {
HL>    }

HL>    public MyClass()
HL>    {
HL>        Initialize();
HL>    }
HL>}
HL>

HL>или еще какой-то вариант?

class MyClass()
{
    private void Initialize(int IntParam,string Name)
    {
       /* 
         тут 100500 строк кода
       */
    }
    // а вот и конструкторы
    public MyClass()
    {
        Initialize(0,"Zero");
    }
    public MyClass(int IntParam)
    {
        Initialize(IntParam,"Int");
    }
    public MyClass(int IntParam,string Name)
    {
        Initialize(IntParam,Name)
    }

}
Re[11]: Стоит ли переносить инициализацию в отдельный метод?
От: vorona  
Дата: 04.07.13 10:02
Оценка:
http://www.rsdn.ru/forum/dotnet/4812371
Автор: abibok
Дата: 10.07.12
Re[3]: Стоит ли переносить инициализацию в отдельный метод?
От: Аноним  
Дата: 04.07.13 10:05
Оценка:
Tom>использовать static-методы вида CreateForA(), CreateForB().
Tom>Это до того момента когда вам тесты понадобится писать. В целом для нормально тестируемого кода надо забыть что такое статический метод, или статическая переменная

А причем тут тесты ? В чем подвох ?
Re[4]: UninitializedException
От: artelk  
Дата: 04.07.13 12:14
Оценка: 48 (2)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, drol, Вы писали:

D>>Это верно только для однопоточной ситуации. В многопоточном случае возможны такие "чудеса", как выполнение конструктора параллельно с финализатором.
S>Чтобы финализатор начал выполняться параллельно с конструктором, нужно, чтобы поток исполнения конструктора дошёл до места, после которого нет обращений к this.
S>Это означает, что если у нас есть недоинициализированный экземпляр, то ссылка на него удерживается в рутах GC, и в лапы финализатора он не попадёт.

Понятно. То есть все будет работать так, как будто финализатор работает после конструктора до тех пор, пока у финализатора не будет какого-нибудь хитрого побочного эффекта, влияющего на наблюдаемое поведение приложения (а не только освобождение занятых системных ресурсов).
Удалось такого добиться на основе глобального изменяемого состояния:

public class A
{
    public static int N;
    private int x;

    public A()
    {
        N = 42;

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine(N);
        //x = N; //uncomment me
    }

    ~A()
    {
        N = 666;
    }
}

static void Main()
{
    new A();

    Console.WriteLine("Done...");
    Console.ReadKey();

    return;
}


В релизе при запуске вне студии выводит 666. Если раскоментировать "x = N;" в последней строке конструктора, то выводит 42.
Re[5]: UninitializedException
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.07.13 17:09
Оценка: -1
Здравствуйте, drol, Вы писали:

D>Ты как-то узко понимаешь инициализацию.


Вот есть поле. Конструктор проставил в него ссылку на объект. А теперь вызывает какие-то методы этого объекта. С этого момента зависимости по this уже нет. Однако инициализация идёт во всю.
Инициализация — это, по определению, изменение состояния объекта. Как только мы перестали менять состояние объекта — его инициализация завершилась.
Если финализатор объекта рассчитывает на какое-то определённое состояние другого объекта — это вина финализатора.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Стоит ли переносить инициализацию в отдельный метод?
От: IB Австрия http://rsdn.ru
Дата: 05.07.13 08:24
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Это до того момента когда вам тесты понадобится писать. В целом для нормально тестируемого кода надо забыть что такое статический метод, или статическая переменная

Ну, без фанатизма.
В данном случае, статический метод ничем не отличается от конструктора. Если у тебя код организован так, что экземпляр этого класса ты инжектишь, а не создаешь прямо в том классе, который хочешь оттестировать, то совершенно пофиг как ты его создаешь в боевом коде, через статический метод или честный конструктор, на тестировании это никак не скажется.
Мы уже победили, просто это еще не так заметно...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.