C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: 型変換の方法について


(過去ログ 173 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■99741 / inTopicNo.1)  型変換の方法について
  
□投稿者/ 河童 (11回)-(2022/05/20(Fri) 14:34:30)

分類:[C#] 

型変換を行って、値の合計を計算したいです。

合計 = エクセルのセルに入力されている値 + リストの値
※セルに値がなければ、そのままリストの値をセルに代入
※リストの値(STRING型)が空白ならば、何もしない

わからないことは、セルの値を代入した変数の型変換です。
文字列に変換、さらに数値に変換しているのですが、
入力文字列の変換が正しくなくてエラーが発生します。

セルの値(数値)を取得して、計算するにはどのようにすればよいですか。
お教えください。よろしくお願いします。

// セルの値
object cell = WS1.Cell(iRow , iCol).Value;
// リストの値
string data = KDataLst[i].kiroku;
// 計算用
int total;

// セルに値がなければ、リストの値
if (cell == null)
{
  WS1.Cell(iRow , iCol).Value = data;
}
else
{
  if (data != "")
  {
    // セルの値+リストの値の合計
        // cellの値の型変換ができずに計算ができない
    total = int.Parse(cell.ToString()) + int.Parse(data);
    WS1.Cell(iRow , iCol).Value = total.ToString();
  }
}

引用返信 編集キー/
■99742 / inTopicNo.2)  Re[1]: 型変換の方法について
□投稿者/ 魔界の仮面弁士 (3369回)-(2022/05/20(Fri) 14:57:43)
No99741 (河童 さん) に返信
> object cell = WS1.Cell(iRow , iCol).Value;
ClosedXML で読み取る場合はその構文で良いのですが、
Excel を COM 参照している場合、そのコードだと COM オブジェクトの
解放漏れになりますよ。


あと、object 型よりも dynamic で受けた方が扱いやすいかも。


> // リストの値
> string data = KDataLst[i].kiroku;
> // 計算用
> int total;
if ( int.TryParse( data, out total) ) {
 // 文字列 data の内容を整数に変換できた場合は
 // ここに到達し、変数 total にその値がセットされる
} else {
 // 文字列 data の内容を整数に変換できない場合には、
 // TryParse は false を返し、変数 total の値は 0 になる
}


data の代わりに cell.ToString() を用いる場合も同様です。
引用返信 編集キー/
■99743 / inTopicNo.3)  Re[2]: 型変換の方法について
□投稿者/ 河童 (13回)-(2022/05/20(Fri) 16:23:16)
No99742 (魔界の仮面弁士 さん) に返信
ご回答ありがとうございました。
下記で計算することができました。

アドバイスにあった「dynamic型」を試してみたのですが、
セルの書式設定の影響なのか「double型」になって、ToStringが使えなかったです。
そのため「object型」のままになっています。

object cell = WS1.Cell(iRow , iCol).Value;
//dynamic cell = WS1.Cell(iRow , iCol).Value;
string stCell = cell.ToString();
int intCell;
int intKiroku;
if (cell == null) // セルの値が空白の場合
{
  WS1.Cell(iRow , iCol).Value = KDataLst[i].kiroku;
}
else // セルの値 + リストの値を合計する場合
{
  // セルの値とリストの値を数値に変換
  if (int.TryParse(stCell, out intCell)) // 文字列 data の内容を整数に変換できた場合
  {
    if (int.TryParse(KDataLst[i].kiroku, out intKiroku))
    {
      // 合計:セルの値 + リストの値
      WS1.Cell(iRow , iCol).Value = intCell + intKiroku;
    }
  }
  else
  {
    WS1.Cell(iRow , iCol).Value = KDataLst[i].kiroku;
  }
}
解決済み
引用返信 編集キー/
■99747 / inTopicNo.4)  Re[3]: 型変換の方法について
□投稿者/ 魔界の仮面弁士 (3372回)-(2022/05/20(Fri) 17:54:31)
No99743 (河童 さん) に返信
> セルの書式設定の影響なのか「double型」になって、ToStringが使えなかったです。

いえいえ、使えますよ。

変数 cell が object 型であれ、dynamic 型であれ、それ以外の型であれ、
 string stCell = cell.ToString();
というコードはコンパイルできるし、きちんと動作するはずです。

もしも変数の中身が null だった場合は、NullReferenceException の例外になりますけれどね。

変数が null だった時にも対応したい場合には、さらに手を加えて
 string stCell = cell?.ToString();
あるいは
 string stCell = cell?.ToString() ?? "";
のように書くこともあります。今回考慮する必要があるかは別ですが。
※「?.」を使った構文は C# 6.0 以降の機能なので、Visual Studio 2015 以降が必要


恐らくは、「.」を打った時には、メンバー名の入力支援が行われないので、
使えないと誤解されたのではないでしょうか?

これは dynamic というものが、コンパイル時ではなく実行時に型が判定されるものであるためです。
コンパイル時には型が決定していないため、「.」を打っても入力支援の一覧には現れませんが、
実際には .ToString() メソッドなどといった、そのデータ型が持つメンバーを問題なく呼び出せます。


そもそも ToString メソッドは、System.Object 型のメンバーです。

ポインタ型を除いたあらゆるデータ型は、すべて「Object 型を継承している」仕様であるため、
それがどのようなデータ型であっても、ToString メソッドは必ず存在しています。


string s;
s = 123.ToString(); // int 型の ToString メソッド
s = 12.34.ToString(); // double 型の ToString メソッド
s = 12.3400M.ToString(); // decimal 型の ToString メソッド
s = s.ToString(); // string 型の ToString メソッド(無意味だけど)
s = DBNull.Value.ToString(); // DBNull 型の ToString メソッド
s = (new object()).ToString(); // object 型の ToString メソッド

dynamic d; // object d; でも可
d = 123; s = d.ToString(); // int 型の ToString メソッド
d = 12.34; s = d.ToString(); // double 型の ToString メソッド
d = 12.3400M; s = d.ToString(); // decimal 型の ToString メソッド
d = s; s = d.ToString(); // string 型の ToString メソッド(無意味だけど)
d = DBNull.Value; s = d.ToString(); // DBNull 型の ToString メソッド
d = new object(); s = d.ToString(); // object 型の ToString メソッド



> そのため「object型」のままになっています。

今回のケースのように ToString することが目的の場合は、むしろ object のままで構わないです。

一応、object と dynamic の違いについて説明しておくと:

object 型だと、変数の中身が double であると確信できる場合であっても、
取り出す際には、元の型への明示的なキャストが必要になります。

 object cell1 = 123.456; // 中身が double だったとして
 // ↓double 型への「ボックス化解除」を行って取り出す
 double dbl1 = 1000.0 + (double)cell1;
 // ↓double 型への「ボックス化解除」を行って取り出した結果を、int にキャストして使う
 int int1 = 1000 + (int)(double)cell1;
 // ↓コンパイルエラー:演算子 '+' を 'double' と 'object' 型のオペランドに適用することはできません
 double dbl2 = 1000.0 + cell1; // ボックス化解除していないので object 型のまま
 // ↓実行時エラー:指定されたキャストは有効ではありません。
 int int2 = 1000 + (int)cell1; // 別の型にいきなり変換することはできない


dynamic 型の場合は、object 型の中身を元の型に戻す手続きが不要になるというだけで。

 dynamic cell2 = 123.456; // 中身が double だったとして
 double dbl3 = 1000.0 + (double)cell2;
 int int3 = 1000 + (int)(double)cell2;
 double dbl4 = 1000.0 + cell2; // 中身が double であることが実行時に判断されるのでエラーにならない
 int int4 = 1000 + (int)cell2; // これも double から int への明示的な変換として扱われる
 // ↓実行時エラー:型 'double' を 'int' に暗黙的に変換できません。明示的な変換が存在します
 int int5 = 1000 + cell2; // 暗黙の型変換を行う機能では無いので、流石にこれは NG
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -