Pull to refresh

Comments 11

Спасибо, я сам раньше думал, что конструктор по умолчанию запрещен в структурах, чтобы сохранялось правило «обнуления» вновь созданной структуры, про time penalty при создании массивов не думал.

Небольшой вопрос, если конструктор по-умолчанию все-таки определен в структуре, то default(StructType) будет его вызывать?
Там почти в самом конце примеры кода с комментариями, когда будет вызываться настоящий конструктор по умолчанию, а когда нет:

// Не вызывется
var cvt = default(CustomValueType);
Ой, извините, не заметил :(
Полезная статья. Хотелось бы еще заметить, что в структуре для инициализации все структуры можно вызвать не только конструктор по умолчанию :this(), но и заменить this внутри конструктора, как бы странно это не выглядело:
 <code class="cs"> struct SomeStruct
{
    private int _i;
    private double _d;

    public SomeStruct(int i)
    {
        this = new SomeStruct();
        _i = i;
        // Поле _d инициализировано неявно!
    }
}
</code> 
Более того, this в конструкторе структуры по сути является out параметром, если «дефолтный» конструктор не вызывается, и является ref-параметром, если «дефолтный» конструктор вызывается:

struct SomeStruct
{
      private int _i;
      private double _d;

    public SomeStruct(int i)
       : this()
    {
        // this в теле метода является ref SomeStruct
        CreateOrUpdate(ref this);
    }

    public SomeStruct(double d)
    {
       // this() не вызывается, значит this является out SomeStruct:
       Create(out this);
    }

    public static void CreateOrUpdate(ref SomeStruct str)
    {
        str = new SomeStruct();
    }

    public static void Create(out SomeStruct str)
    {
        str = new SomeStruct();
    }
}
Как-то вы некоторые моменты сложно расписали. :) Одна из причин такого хитрого существующе/отсутствующего конструктора по умолчанию в частности ещё состоит в том, что структуры копируются при присвоении/передаче в качестве параметра. Что в принципе приводит с одной стороны к созданию нового объекта, с другой стороны конструктор вызываться не будет.
Как результат, наличие явного конструктора без параметров может привести к некоторым логическим проблемам.
В С++, например, есть четкое разделение между конструктором компирования и конструктором по умолчанию и никаких логических проблем при этом нет.

Здесь есть такое же разделение, но при этом конструктор копирования «генерируется» не компилятором, а CLR. Так что я не вижу никакой связи между отсутствием конструкторов по умолчанию в языке C# и передачей по значению с автоматическим копированием всех полей структуры.
конструктор копирования «генерируется» не компилятором, а CLR
Вот это как раз и есть принципиальная разница. CLR генерирует данный конструктор, но это её личное дело, как она это делает. Программист на C# без хаков повлиять на это никак не может.
Я так и не понял, какая связь между конструктором по умолчанию и процессом копирования?

Конструктор по умолчанию устанавливает исходный вариант создаваемому объекту, конструктор копирования делает побитовую (как в случае структур) копию объекта, что автоматически сохраняет его инвариант.

При копировании не должен вызываться конструктор по умолчанию, этого не происходит в том же С++, и этого не происходит в .NET при бинарной или DataContract десериализации объекта. Это нормальное и ожидаемое поведение.

Еще раз: к каким логическим проблемам приведет наличие явного конструктора без параметров в контексте передачи структур по значению и почему его можно создать в IL-е?
этого не происходит в .NET при бинарной или DataContract десериализации объекта. Это нормальное и ожидаемое поведение.
Там можно рулить всякими ISerializable и .ctor(SerializationInfo info, StreamingContext context), т.е. получить вызов конструктора или заменяющего его метода.

к каким логическим проблемам приведет наличие явного конструктора без параметров в контексте передачи структур по значению
Проблемы могут быть в том, что он как раз не вызывается при создании копии объекта. Т.е. наличие некоторой инициализации в конструкторе по умолчанию может привести к ошибкам при отсутствии его вызова. В C# в этом месте решили явно ограничить поведение ради более стабильного поведения.

почему его можно создать в IL-е
Потому что IL гораздо функциональнее чем C#, и в других языках могут быть совершенно другие механизмы работы со структурами.
Кстати, на на конструктор копирования структуры я даже не знаю, как с хаками повлиять. Разве что через CLR Profiling API, но даже в этом я не очень уверен.
Sign up to leave a comment.

Articles