Home / C# 始めました

都度、書き留めいた日記分も移動。

参考:
Reference Source(.NET Framework source code online)
連載 C#入門
C#のジェネリクスでできないこと

バージョン

何をもってバージョンと言っておるのかさっぱり判らない。

Visual Studio 2012, C# 5.0
Visual Studio 2015, C# 6.0, .NET Framework 4.6, Windows 10
Visual Studio 2017, C# 7

C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322
 2003/02/21 10:20 49,152 csc.exe
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
 2008/07/25 11:16 80,376 csc.exe
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319
 2010/03/18 13:16 1,972,552 csc.exe

Microsoft(R) Visual C# .NET Compiler version 7.10.3052.4
for Microsoft(R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.3053
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

FileStream クラス

partial を使ってみる

(2017-08-27)
邪悪な仕様だと思っていたが、参考ソースが「クラス概念なんぞ何じゃらほい」orz
なので整理の目的で使ってみた。

とりあえずメソッドのみファイル分けして見通しは良くなった。
メンバ変数も出来るのだろう。
只、ファイル単位でメンバ変数のスコープが決まる訳では無さそうだから止めておくのが吉かも…

元々、フォーム使用時のリソース的な部分を分離したいが為に追加された仕様かと思っていて、そう言うファイルのみ partial キーワードが付く物、と思っていたが、そうではないようだ。

partial キーワードは、すべての部分で使用する必要があります。

つまり、partial を使うなら、そのクラスの定義の全てに partial キーワードを付けないといけない。

ま、新規設計なら使わぬのに越した事はない。が、フォームクラスの雛形は付いているだろうから結局、世の殆どのフォーム使用コードは partial キーワード付きと言う有様なのだろう。

オーバーロード関数

(2011-10-06)
C# はオーバーロードを継承するんですよね、これが。
一方、C++ はオーバーロードは継承されない。参考:C++ ラビリンス

バギーな発想じゃあるまいか…結構やばいと思う。

引数に関してはやたら ref やら out やら厳格過ぎる位の規則を設けているのに対して...

構造体

(2018-02-28)
何と継承出来ない( ゜Д゜;)!?
何故? アンダース君の至上命令なのだろうか…

enum

(2017-9-16)
何故か使えない~と思っていたら、関数(メソッド)の中では書けないだと…

通常、列挙型は名前空間内に直接定義して、名前空間内のすべてのクラスが共通の利便性でアクセスできるようにするのが最も適切です。 ただし、列挙型はクラスまたは構造体内に入れ子にすることもできます。

メソッドには書けません、と言えばいいものを… C から良いとこ取りしたんだから明記して欲しいね。

大抵は int である、と言いながら要素を数値と見なすにはキャスト (int) しないといけない。逆に数値を列挙要素とするにもキャスト。
こんなにキャストを要するなんて、何かがおかしい。

@IT - C#入門 第16回 列挙型の活用 http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_016/csharp_abc01.html
を見てみる。
すると、メンバには漢字も使えると…

namespace cs1 {
//  namespace ns1 {
        enum Era { 明治, 大正, 昭和, 平成 } //}
    
    class Class1 {
        [STAThread] static void Main(string[] args) {
//          Era t = Era.平成;
            Console.WriteLine((int)Era.平成);
            Console.WriteLine(     Era.平成.ToString());
//          foreach (int i in Enum.GetValues(typeof(Era)))
            foreach (Era i in Enum.GetValues(typeof(Era)))
                Console.WriteLine(i);
        } } }

ToString()を使えばちょっとした文字配列の代替になりそう。
と、調子に乗って使ってみた処、foreach + Enum.GetValues は列挙要素値の小さい順で返すようだ。
見た目の定義順を期待してはいけない。

さて、或る値が列挙要素に含まれるか、を調べるには
Console.WriteLine(Enum.IsDefined(typeof(Era), 3));
この場合はキャスト無く通してしまう処が(何だよ)って感じる。

C#のジェネリクスに触れる

C++ テンプレートとはまるで違う。おいそれとは使えない。 使う場面は極限られるだろう。

-------------

(2011年?)
C# に慣れていないのにジェネリクスを使おうと言うのも、やや無謀なんだけども、まぁ、コンパイルさえ通れば一応の安心感は得られるので、見通しの良さを買って使う事にした。

C++ のノリで書いてみた処、早速、制約の部でエラーに引っ掛かった。
C++ のテンプレートで型パラメータに何が適用出来るか明示できればいいなぁ、と思うのは誰しもな訳で、C# では キーワード where で指定するそうな。

複数の制約の例:

class SuperKeyType<K, V, U>
    where U : System.IComparable<U>
    where V : new()
{ ... }

ん~、C# に慣れていないだけに難しい。
正直、ジェネリクスなルーチンに、それ程時間を費やせない...
だったら使うなと言われれば身も蓋も無し orz

ふと思ったのだが、大体、ジェネリクスやらテンプレートやら、そんな元のコードと言うのは特定のコードで書き始めるのが多いと思うんですよね。んで、そこから一般化すると。

仰々しく言えば、所謂、特殊相対性理論から一般相対性理論への道程に似ている訳で、と言っても、ジェネリクス化やテンプレート化は機械的な作業(思考)が大部分だと思います。

ならば、そんな無機質な作業はコンピュータがやるべきじゃないかと... 完璧でなくてもいいからヒントを与えるレベルで良い訳です。 残念ながらそんなツールにはお目にかかった事がないが ... 良いツールになると思うんですがねぇ...

忙しくて色々試せないせいもあるが、どうもこの制約という奴は胡散臭い匂いがする。
だって(ある程度)汎用になると思うコードが、実は文法上、万能でないという処はコンパイラが一番良く判るはずな訳です。それに where を書かない場合、C# コンパイラはあらゆる型に適合するのだと言う前提に立つようなんですよね。有限のインスタンス化の前に…。

人間様を支援するのが本来の目的だと思うのだが、どうも C# は規律に従わない人間を罰するかの如く態度に出て面白くない。

ジェネリクス:余談

Visual Studio 2005 に付いていた MSDN の「C# プログラミング言語の将来の機能」- 複数の制約 には

public class Dictionary<KeyType, ValType> where
KeyType :IComparable,
KeyType :IEnumerable,
ValType :Customer
{

と言う風に説明されているが、製品版でこのようにカンマで区切るとエラーになる。開発中の文書なので、途中で変更されたのだろう。

この文書には、他の実装と比べ、C# のジェネリクスが全ての点で勝っているかの如く書かれてある。
ま、「C++ テンプレートと C# ジェネリックの違い (C# プログラミング ガイド) 」で C# が劣っている?点が正直に書かれてある。流石に Java との比較は無い。

ジェネリクス:VB

(2016-04-26)
何だかなぁ…
VBと言わずC#やJavaも同じ状況なんだろうが…

VBと言えば画面・フォーム、コントロールへばりばりアクセスし、そんでもってジェネリックで共通化出来れば…
なんて期待してもダメ出し食らう orz

C++テンプレートなんかとは根本的に仕組みが違う。
あっちは謂わば高級プリプロセッサだから、パラメータT の継承関係なんかクソくらえ!って感じで、筋が通ればコンパイル出来ちゃう。それ判っててやる分にはとても重宝する。

でもジェネリックって… 継承と言うか型にべったり。
字面だけしか見てくれないし、実行時になってエラー表示するも多々有り。
何の為のコンパイラか?

DataSet

(2017-10-7)
何それ?

第4回 データセットを使ったデータベース・アクセス
http://www.atmarkit.co.jp/ait/articles/0309/06/news002.html
http://www.atmarkit.co.jp/ait/articles/0309/06/news002_2.html

第2回 .NETデータ・プロバイダによるデータベースのアクセス http://www.atmarkit.co.jp/ait/articles/0305/16/news003.html

SQL Server用、OLE DB用、ODBC用、Oracle用と用意されている。

Visual Studio でウィザードを使って DataSet を追加し、テーブルを作りこむとテンコ盛りの DataSet1 クラスなんかが出来る。

テーブル Hoge を作るとこんな感じで自動生成される↓

public partial class DataSet1
 private HogeDataTable tableHoge;

public partial class HogeDataTable
public partial class HogeRow

テンコ盛りの DataSet1 クラスは列データのプロパティアクセスが用意されるが、これ、例外が付いておりウザイ。どうして null を返すの嫌がるのか…
string なら null を返しても良いが、そうでない場合は返せないだと…
逆じゃね?と思うのだが… 何だかんだでテンコ盛り DataSet1 クラスは使う気がしない。

曲者が *DataAdapterクラス。
*DataAdapterクラスは素の DataSet しか相手にしない模様。
Fill がそう。でもキャストした変数を渡すと受け付けた。当たり前だが…
どう使うのが正しいのか判らぬ orz

ファイル処理

(2016-05-22)
System.IO.File にファイル操作関係がまとまってるようだ。static メソッドが多い。
Open が fopen に近い System.IO.FileStream を返す。
FileStream コンストラクタでも同様じゃないかと思われる。

例外んとこは吟味要。 Dispose だったか、も併せて。

System.IO.FileStream fs = null;
string err;

try
{
    if (System.IO.File.Exists(filename))
    {
        fs = System.IO.File.Open(filename,
                       System.IO.FileMode.Open,
                       System.IO.FileAccess.Read,
                       System.IO.FileShare.ReadWrite);
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("存在しない。");
    }
}
catch (System.ArgumentNullException e)        { err = e.ToString(); }
catch (System.ArgumentOutOfRangeException e)  { err = e.ToString(); }
catch (System.ArgumentException e)            { err = e.ToString(); }
catch (System.IO.PathTooLongException e)      { err = e.ToString(); }
catch (System.IO.FileNotFoundException e)     { err = e.ToString(); }
catch (System.IO.DirectoryNotFoundException e){ err = e.ToString(); }
catch (System.IO.IOException e)               { err = e.ToString(); }
catch (System.UnauthorizedAccessException e)  { err = e.ToString(); }
catch (System.Security.SecurityException e)   { err = e.ToString(); }
catch (System.Exception e)                    { err = e.ToString(); 
                                                throw; 
}
finally
{
    if (fs != null)
        fs.Close();
}

処で HResult が protected なのは何故だろう… と言うよりおかしいとしか思えない。
ググっても簡単な方法が判らないので強引なサブクラスを作ってみる…

MSDN に拠ると 「派生クラスでは、少なくとも 4 つのコンストラクターを定義せよ」 とあるのでコピペして作る。

public class Hoge : System.Exception
{
    public Hoge() : base() { }
    public Hoge(string message) : base(message) { }
    public Hoge(string message, System.Exception inner) : base(message, inner) { }
    protected Hoge(
        System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) { }

    public int code() { return this.HResult; }
    public static int GetHResult(System.Exception e)
    {
        Hoge hr = new Hoge(e.Message, e);
        return hr.code();
    }
}

ここまでしないと HResult を渡さない仕様って…何なのだろう。 VBスクリプトだかJスクリプトだったか、当たり前のように HResult を返していた気がするのだが。

そもそも「例外」とは文字通り予想外とか想定外なのであって、それを予め想定する事が間違ってるような…
コンピューティングに限らず「起こり得る事は出来るだけ避ける」のが正しい道と思う。


(2016-05-23)
周囲の人に意見を求めた処、.NETでは例外をコード化するのは望む処ではない、と聞いた。
むぅ~、一理有るようで、でも納得しかねる…
そりゃぁコンピューティングが常に画面と対話するものならいいですよ。
無人稼動も有ればハード故障も有りでしょう。

何となく .NET と言うか MS は ┐( ̄ヘ ̄)┌ かなぁ~と。

腹立たしいTextFieldParser

結構まとまった機能を持つパーサーだと思っていたら...
TextFieldParser.ReadFields メソッドは空行に出会ったら、空行でない行まで読み込みを自動的に繰り返し、読み込んだ次の行をカレント行にマークする。

此処までは良い。scanf 系と同じだ。

処が最終行で LineNumber プロパティを見ると -1 が返される。
つまり、読み込めた行が何行だったのか知る術が無い。

困った設計だ orz

色々不満はあるが、LineNumber が -1 を返すのは設計ミス。
それは嫌だと言うなら読み込んだ行を返す ReadLineNumber プロパティを追加すべきだ。

どうも MS の技術者は思い付きで設計してるみたいだ...


(2018-2-12)
ソース見ようとしたがヘッダ部しか見当たらない。
しかも namespace は Microsoft.VisualBasic.FileIO(Microsoft.VisualBasic.dll) だ、うへっ。

テキストファイルの行数を高速に数える

テキスト内容はひとまず置いて、行数だけ早く知りたい場合が有る。
特に巨大なファイルだと尚更。
ReadLine なんぞで読んで数えるのは無駄。素人のやる事だ。

調べると .NET Framework 4.0 以降 で File.ReadLines なんてメソッドが見つかるが、これは列挙前に行数は得られないのではなかろうか…
そこで古典的な C/C++ のアプローチ「適当なバッファに読み込みながら改行コードを探す」で数えてみる。
Shift-JIS 前提。IndexOf() も使ってみる。

int NumberOf(string file)
{
    FileStream fs = new FileStream(file, …
    byte[] buffer = new byte[4096];
    bool eot = true;
    int num = 0;    // 改行数。

    for (;;)
    {
        int n = fs.Read(buffer, 0, 4096);
        if (n <= 0)
        {
            if (!eot)
                ++num;
            break;
        }
#if true
        for (int p = 0; p < n; ++p)
        {
            if (buffer[p] == (byte)'\n')
                ++num;
        }
#else
        for (int p = 0; p < n; ++p)
        {
            p = Array.IndexOf(buffer, (byte)'\n', p, n - p);
            if (p < 0) break;
            num++;
        }
#endif
        eot = buffer[n - 1] == (byte)'\n';
    }

    return num;
}

見ての通り Array.IndexOf を使ってもシンプルにはならない。
最後の引数 count は省略すれば配列の最後まで探すが、Read が指定サイズを読むとは限らない為、省略出来ない。
むぅ~ 無闇にクラスライブラリ使えばイイというものではない。

eot はバッファ中の最後が改行で終わっていたかどうか、を示す。
改行で終わっていなければ行数は1つ多く数えるべきなので…。
丸で読めない場合に誤って1行と返さぬよう初期値は true とする。

ショボイ環境で時間測定してみると 38MB, 17万行のファイルで 300 msec 要した。
wc コマンドより気持ち遅い感じ。
awk 'END{print NR}' より早い。
当然だがテキストエディタの読み込みより断然早い。まずまずか。

Task, ...

プロセス/スレッドを改めたようだから、簡単・安全に作り直されているかと期待したが… 情報が氾濫していて難しい。
.NET になって余計に混乱し始めたんじゃなかろうか…
バージョンによって使えなかったり訳ワカメ。

kekyoの丼氏の できる!C#で非同期処理(Taskとasync-await) が良さそうだ。

.NET Framework 4 xxx: error CS1061: 'Task' に 'GetAwaiter' の定義が含まれておらず、型 'Task' の最初の引数を受け付ける拡張メソッド 'GetAwaiter' が見つかりませんでした。… yyy: error CS1061: 'FileStream' に 'ReadAsync' の定義が含まれておらず、型 'FileStream' の最初の引数を受け付ける拡張メソッド 'ReadAsync' が見つかりませんでした。…

FTP

(2017-09-03)
FTP サーバーに有るファイル一覧を見る、となれば ls コマンド。
所謂 LIST コマンドを送信する。これを C# でやるには System.Net.FtpWebRequest.Method に "LIST" を与えるそうな。
大抵は System.Net.WebRequestMethods.Ftp.ListDirectoryDetails の定数を使った例が多い。

さて、問題は「サブディレクトリは要らねぇ」って場合にどうやるか? 考えるまでも無かろう、と思っていたら…考えなきゃいけないんですねぇ orz

ちょっと探した処、返された各行の1文字目が "d" で始まるか見よ! との事。 http://d.hatena.ne.jp/chaichanPaPa/20071031/1193829219

何故かと言えば、大抵のサーバーは次のような書式の文字列を返すからで御座る。 (コマンドラインで見える通りだ)

drwxr-xr-x   2 hoge     503           125 May 21 08:33 .
drwxr-xr-x  15 hoge     503          4096 May 25 06:02 ..
-rw-r--r--   1 hoge     503          4755 May 21 08:33 aaa.html
-rw-r--r--   1 hoge     503         19732 Aug 27 02:10 index.html

尤も、IIS なら MS-DOS スタイルも返せる仕様らしいが、そんな事を知ってか知らずか "<DIR>" を含むかどうか無邪気に調べたりしている人も居る。 畏らくこんなの返すのを前提にしている。

2017/08/27  14:29    <DIR>          .
2017/08/27  14:29    <DIR>          ..
2017/05/20  21:19             4,755 aaa.html
2017/08/27  02:03            19,732 index.html

やるならばせめて第3欄に絞って見て欲しいものだ。

そもそも FTP はコマンドラインで対話しながらの環境を想定されているから、シェルコマンドの ls と同じ表現なのは当たり前なんだが、そう言う事ならディレクトリーや通常ファイル以外も有るだろう!って話し。

一例として AIX の ls を見てみると、
https://www.ibm.com/support/knowledgecenter/ja/ssw_aix_61/com.ibm.aix.cmds3/ls.htm
結構有る…
 d:ディレクトリー
 b:ブロック・スペシャル・ファイル
 c:キャラクター・スペシャル・ファイル
 l:シンボリック・リンク
 p:先入れ先出し (FIFO) スペシャル・ファイル
 s:ローカル・ソケット
 -:通常ファイル
一覧のファイルを GET するからディレクトリーだけ除外すればOK、なんて考えているとマズいんじゃないか?
通常ファイルは兎も角、シンボリック・リンクファイルも GET したい場合が殆どでしょう。
- と l を対象にすれば宜しいのか…

さて本題は、LIST コマンドなんぞは定数化しておきながら、その応答については勝手にしてくれ、と言わんばかりの態度。
LIST の応答解析が簡単でないのは判るが、じゃぁエクスプローラは FTP サイトを一覧表示出来ないのか?
そんな事は無い。各FTPクライアントだってちゃんと表示出来ている。
なのにフレームワークが何故出来ないのか? やらないのか?

ここまで書いてふと…
(.NET が現れる以前ってどうしてたよ?)…そう、WinInet に FtpFindFirstFile() が有った、否、今でも有る。
これが、お馴染みの WIN32_FIND_DATA 構造体に詰めて返してくれていた。
LIST レスポンスを解析する必要なんて無かったのである。
.NET は小奇麗で現代風に見えるかも知れないが退化しとるわ。

手が回らないんだ、と言うなら Win32 に依存してでも機能継承すべきじゃないか…

とか言うと「64bit環境じゃ動かねーんだよ!」と返されるかも知れないが、それなら「.NET なんか止めて Win64 にしやがれ!」と切り返しておく。

.NET は何だか煙に巻かれた気がして好きになれない。


Home / C# 始めました

© 2008 usskim    http://usskim.web.fc2.com/
inserted by FC2 system