15

以下を考えると:

[<DataContract>]
type TweetUser = {
    [<field:DataMember(Name="followers_count")>] Followers:int
    [<field:DataMember(Name="screen_name")>] Name:string
    [<field:DataMember(Name="id_str")>] Id:int
    [<field:DataMember(Name="location")>] Location:string}

[<DataContract>]
type Tweet = {
    [<field:DataMember(Name="id_str")>] Id:string
    [<field:DataMember(Name="text")>] Text:string
    [<field:DataMember(Name="retweeted")>] IsRetweeted:bool
    [<field:DataMember(Name="created_at")>] DateStr:string
    [<field:DataMember(Name="user", IsRequired=false)>] User:TweetUser
    [<field:DataMember(Name="sender", IsRequired=false)>] Sender:TweetUser
    [<field:DataMember(Name="source")>] Source:string}

で逆シリアル化するDataContractJsonSerializer(typeof<Tweet[]>)と、 User フィールドまたは Sender フィールドのいずれかが null になります (少なくとも、デバッガーが私に伝えていることです)。

私が次のように書こうとすると:

    let name = if tweet.User <> null 
                  then tweet.User.Name
                  else tweet.Sender.Name

コンパイラは次のエラーを出力します:「型 'TweetUser' には適切な値として 'null' がありません」

この場合、null 値をテストするにはどうすればよいですか?

4

3 に答える 3

19

@Tomasの回答を周期的に展開するには;-]

let name = if not <| obj.ReferenceEquals (tweet.User, null)
              then tweet.User.Name
              else tweet.Sender.Name

また

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null)

Unchecked.defaultof<_>正しいことを行っており、レコード タイプに対して null を生成しています。問題は、既定の等価演算子が一般的な構造比較を使用することです。これは、F# 型を使用するときに常に F# の規則に従うことを期待しています。いずれにせよ、null チェックは、そもそも参照比較のみを保証します。

于 2012-05-25T00:00:31.087 に答える
15

@ildjarn によるコメントに詳細を追加すると、エラー メッセージが表示されます。F# では、nullF# で宣言されている型の値としての使用が許可されていないためです。これの動機は、F#が純粋な F# プログラムからnull値 (および)を削除しようとすることです。NullReferenceException

ただし、F# で定義されていない型を使用している場合は、引き続き使用できます(たとえば、引数として受け取るnull関数を呼び出す場合は、それを指定できます)。これは相互運用性のために必要です。.NET ライブラリに渡すか、結果としてそれを受け入れる必要がある場合があるためです。System.Randomnullnull

あなたの例では、は F# で宣言された (レコード) 型であるため、言語はtype の値としてTweetUser扱うことを許可していません。ただし、リフレクションまたは C# コードから値を取得することはできるため、F# は、通常は値を持つべきではない F# レコードを含む、任意の型の値を作成する「安全でない」関数を提供します。これが関数で、これを使用して次のようなヘルパーを実装できます。nullTweetUsernullnullnullUnchecked.defaultOf<_>

let inline isNull x = x = Unchecked.defaultof<_>

または、属性で型をマークすると、F#で宣言された型であっても、その特定の型の値としてAllowNullLiteral許可する必要があることを F# コンパイラに伝えます(通常は許可されません)。nullnull

于 2012-05-24T23:42:08.740 に答える