Переопределение соответствия шаблону Exception.Message/Exception

Я пытаюсь сопоставить образец с исключением в его определении. Возможно ли что-то вроде следующего с использованием синтаксиса исключений F#, или я должен создать подкласс Exception?

Я ожидал, что это сработает:

exception CoordErr of int * int
    with
        override this.Message = 
            let CoordErr(x, y) = this
            sprintf "(%i %i)" x y //ERROR

Но выдаёт ошибки:

Значение или конструктор "x" не определено
Значение или конструктор "y" не определено

ИЗМЕНИТЬ

Я также попытался добавить скобки:

let (CoordErr(x, y)) = this

Но это дает ошибку:

Ожидалось, что это выражение будет иметь тип exn, но здесь имеет тип CoordErr.

ОБНОВЛЕНИЕ

Следующее работает, но не идеально:

exception CoordErr of int * int
    with
        override this.Message = 
            sprintf "(%i %i)" this.Data0 this.Data1

Есть ли другой способ сделать это?

ОБНОВЛЕНИЕ 2

Принимая во внимание ответ kvb, я полагаю, что мог бы сделать следующее, чтобы проглотить предупреждение incomplete matches:

exception CoordErr of int * int
    with
        override this.Message = 
            match this :> exn with
            | CoordErr(x, y) -> sprintf "(%i %i)" x y
            | _ -> Unchecked.defaultof<_>

person Daniel    schedule 17.02.2011    source источник
comment
Я бы изменил его с Unchecked.defaultof<_> на failwith "impossible"   -  person Brian    schedule 17.02.2011


Ответы (3)


Ваша первая попытка не работает, потому что вы определяете функцию let-bound с именем CoordErr, которая скрывает конструктор исключений, а это не то, что вам нужно.

Ваша вторая попытка почти работает. К сожалению, определения исключений работают не совсем так, как размеченные объединения: при сопоставлении шаблонов с конструктором исключений выражение, которое вы сопоставляете, должно иметь тип exn (а не определенный подтип исключения). В вашем случае вы пытаетесь сопоставить this (типа CoordErr) с конструктором CoordErr. Как это для обходного пути?

exception CoordErr of int * int
    with
        override this.Message = 
          let (CoordErr(x,y)) = upcast this
          sprintf "(%i %i)" x y
person kvb    schedule 17.02.2011
comment
Это здорово (предупреждение incomplete pattern matches немного раздражает, но да ладно). Можете ли вы объяснить необходимость upcast? - person Daniel; 17.02.2011
comment
Неважно. Вы, видимо, объясняли это, когда я спрашивал. :) - person Daniel; 17.02.2011
comment
@kvb - я обновил вопрос кодом, который позволяет избежать предупреждения. Есть ли лучший способ сделать это? - person Daniel; 17.02.2011
comment
@Daniel - я согласен, что поведение немного странное (и очень тонкое). В каком-то смысле это кажется последовательным: let e = CoordErr(1,2) приводит к тому, что e имеет статический тип exn, а не CoordErr, поэтому имеет смысл использовать CoordErr для уничтожения exn значений при использовании в качестве шаблона. - person kvb; 17.02.2011
comment
@kvb - я этого не понимал. Очень хорошо знать. В свете этого есть смысл. - person Daniel; 17.02.2011
comment
@Daniel - вместо этого я бы использовал #nowarn "25", поскольку вы знаете, что в этом случае шаблон всегда будет совпадать. - person kvb; 17.02.2011
comment
@kvb - я полагаю, что в идеале это должно быть в отдельном файле, поскольку #nowarn применяется ко всему файлу. - person Daniel; 17.02.2011
comment
@kvb - Спасибо за ваш ответ - как обычно проницательный. - person Daniel; 17.02.2011

Похоже, что имена аргументов конструктора и доступ к соответствующим полям работают:

exception CoordErr of x : int * y : int
    with
        override this.Message = 
            sprintf "(%i %i)" this.x this.y

Я понимаю, что это не решение для сопоставления с образцом, но оно отвечает на часть вашего вопроса «Overriding Exception.Message». :)

person David Tchepak    schedule 19.08.2016
comment
Это, вероятно, самое чистое решение, но именованные поля объединения еще не были добавлены в F #, когда я задал вопрос. - person Daniel; 21.08.2016
comment
Понял, просто добавил это для будущих посетителей :) - person David Tchepak; 21.08.2016

Вы можете использовать сопоставление шаблонов с учетом исключения для попытки с выражением

exception CoordErr of int * int
    with
        override this.Message = 
            try raise this with CoordErr(x, y) -> sprintf "(%i %i)" x y
person philderbeast    schedule 05.05.2013
comment
Это далеко не идеально, так как выращивание и ловля занимают гораздо больше времени, чем обычные операции. Даже если это делается только один раз, это очень плохая привычка. - person Ramon Snir; 05.05.2013