DOBON.NETプログラミング道掲示板

[ 最新記事及び返信フォームをトピックトップへ ]

■34003 / inTopicNo.1)  Object型からDecimalへの変換
  
□投稿者/ ちゅう太 一般人(1回)-(2018/10/10(Wed) 23:42:01)
  • アイコン環境/言語:[Windows7/.NET Framework 4.6.2] 
    分類:[.NET] 

    クラスを新規に作成し、Valueプロパティ(Object型)を作成しました。
    そのValueプロパティのSetterでObject型からDecimal型に変換したいのですが、
    皆様はどのように変換されているのでしょうか?
    (Valueプロパティには何型がセットされるかわからないものとした場合)

    現在はConvert.ToDecimal(object) を Try Catch End Try で挟んでいます。
    Object型をToStringメソッドでString型にしてから、Decimal.Parse等で変換するのでしょうか?

    Public Interface IInterface()
    Property Value() As Object
    End Interface

    Option Strict On
    Public Class ClassDecimal
    Implements IInterface

    Private myValue As Decimal = 0

    Public Property Value() As Object Implements IInterface.Value
    Get
    Return myValue
    End Get
    Set(value As Object)
    ' Decimalに変換できない場合はゼロとする
    If value Is Nothing Then
    myValue = 0
    Else
    Try
    myValue = Convert.ToDecimal(value)
    Catch
    myValue = 0
    End Try
    ' もしかして以下のほうがスマート?
    ' Dim result As Decimal = 0
    ' If Decimal.TryParse(value.ToString, result) Then
    ' myValue = result
    ' Else
    ' myValue = 0
    ' End If
    End If
    End Set
    End Property
    End Class

マルチポストを報告
違反を報告
引用返信 削除キー/
■34009 / inTopicNo.2)  Re[1]: Object型からDecimalへの変換
□投稿者/ 魔界の仮面弁士 大御所(1156回)-(2018/10/11(Thu) 17:37:43)
  • アイコンNo34003に返信(ちゅう太さんの記事)
    > そのValueプロパティのSetterでObject型からDecimal型に変換したいのですが、
    > 皆様はどのように変換されているのでしょうか?
    > (Valueプロパティには何型がセットされるかわからないものとした場合)

    「Decimal 以外の値」、たとえば String や Integer がセットされていた場合に
    変換を許容するのか否かで変わってきます。

    Decimal や Decimal? しか認めないなら、TryCast すれば良いですし、
    String からの変換が前提なら、Decimal.TryParse に文字列を渡しますし、
    何でも良いのでとにかく変換を試みるなら、CDec ですね。


    > Public Interface IInterface()
    この括弧は誤記でしょうか。それとも Of が省略されているとか?

    Public Class ClassDecimal
     Implements IInterface(Of Decimal)
     Public Property Value As Decimal Implements IInterface(Of Decimal).Value


    > 現在はConvert.ToDecimal(object) を Try Catch End Try で挟んでいます。
    「Decimalに変換できない場合はゼロとする」という仕様なのですね?



    > Object型をToStringメソッドでString型にしてから、Decimal.Parse等で変換するのでしょうか?
    Decimal.TryParse は、変換失敗時に出力引数へ Decimal.Zero を渡すことを
    保証していますから、If 文すら不要に思えます。
    https://msdn.microsoft.com/ja-jp/library/9zbda557.aspx

    加えて、出力先を Me.myValue にすることで、下記のように単純に書くことができます。


    'VB2015 以降
    Set(value As Object)
     Decimal.TryParse(value?.ToString(), myValue)
    End Set

    'VB2008〜VB2013
    Set(value As Object)
     Decimal.TryParse(If(value, "0").ToString(), myValue)
    End Set


    > ' もしかして以下のほうがスマート?
    注意点として、CDec / Convert.ToDecimal / Decimal.TryParse による処理は、
    同じ結果が保証されるものではない事を念頭において使い分ける必要があります。


    たとえば、value の中身が True だった場合、
    Convert.ToDecimal は「Decimal.One」となりますが、
    CDec は「Decimal.MinusOne」を返す仕様です。
    Decimal.TryParse では変換されずに「Decimal.Zero」になります。

    value の中身が vbCritical だった場合、
    CDec と Convert.ToDecimal は「16D」となりますが、
    Decimal.TryParse では変換されず「Decimal.Zero」になります。

    value の中身が "&H21" だった場合、
    CDec は「33D」となりますが、Convert.ToDecimal は例外。
    Decimal.TryParse は変換されず「Decimal.Zero」です。

    value の中身が 1.0R Mod 0.1R だった場合、
    CDec と Convert.ToDecimal は有効桁数 2 桁で「0.10D」になりますが
    Decimal.TryParse(value.ToString(), result) だと
    文字列化の際に末尾 0 が落ちるので「0.1D」になります。
    このケースでは、誤差を抑えるために、R 書式(ラウンドトリップ文字列)を用いて
    Decimal.TryParse($"{value:R}", result) のようにすると、
    「0.09999999999999995D」になりますが…汎用的では無くなりますね。

    ということで、TryParse を用いて変換する方法については、
    さらにその前の文字列化変換についても一考の余地があります。

    オブジェクトを文字列へ変換する手段としては、たとえば、
    obj.ToString() と Convert.ToString(obj) と CStr(obj) などがありますが、
    これら 3 つもまた、それぞれ異なる結果になりえますね。
違反を報告
引用返信 削除キー/
■34010 / inTopicNo.3)  Re[2]: Object型からDecimalへの変換
□投稿者/ ちゅう太 一般人(2回)-(2018/10/12(Fri) 00:03:11)
  • アイコン魔界の仮面弁士様
    この度は丁寧かつ詳細な説明ありがとうございます。

    > Decimal や Decimal? しか認めないなら、TryCast すれば良いですし、
    > String からの変換が前提なら、Decimal.TryParse に文字列を渡しますし、
    > 何でも良いのでとにかく変換を試みるなら、CDec ですね。
    CDec 等のデータ型変換関数は VB6の匂いがして、
    なんとなくですができるだけ使用をさけています。
    (といいながら、CTypeは結構使ったりしているので、矛盾してますね。)

    >>Public Interface IInterface()
    > この括弧は誤記でしょうか。それとも Of が省略されているとか?
    >
    > Public Class ClassDecimal
    >  Implements IInterface(Of Decimal)
    >  Public Property Value As Decimal Implements IInterface(Of Decimal).Value
    すいません。単純なタイプミスです。

    せっかくご教授いただいたので、インターフェースのジェネリック勉強したいと思います。
    ありがとうございます。

    > 「Decimalに変換できない場合はゼロとする」という仕様なのですね?
    はい。そのとおりです。
    「変換できない場合はエラーをThrowする」というのも考えたのですが、やめました。
    (それほど深い理由はありません。エラーのハンドリングがめんどうかな?というくらいの理由です。)

    > Decimal.TryParse は、変換失敗時に出力引数へ Decimal.Zero を渡すことを
    > 保証していますから、If 文すら不要に思えます。
    > https://msdn.microsoft.com/ja-jp/library/9zbda557.aspx
    Decimal.TryParseが失敗したとき、出力引数がDecimal.Zeroになること初めて知りました。
    別のソースで「Decimal.TryParseが失敗したときには出力引数は元通り」と勝手に解釈しているところがありました。
    ご教授感謝いたします。

    > 'VB2015 以降
    > Set(value As Object)
    >  Decimal.TryParse(value?.ToString(), myValue)
    > End Set
    >
    > 'VB2008〜VB2013
    > Set(value As Object)
    >  Decimal.TryParse(If(value, "0").ToString(), myValue)
    > End Set
    これはとてもシンプルでとっても気持ちいいですね。

    これまでは、「一回String型に変換して、Decimal型に変換する」というのは2回変換をかけるので、
    「どうかなぁ?」と思っていました。
    でもよく考えてみると「Object型になにが入っているかわからない」状態なので
    、(扱いやすい?)文字列に変換かけるというのも道理かな?と思うようになってきました。

    大変参考になりましたし、
    知らないことをたくさんご教授いただきました。

    本当にありがとうございました。


解決み!
違反を報告
引用返信 削除キー/



トピック内ページ移動 / << 0 >>

このトピックに書きこむ

Mode/  Pass/


- Child Tree -