2016年03月02日

猿でもわかるC#プログラミング 第3版



プログラミングの入門書として有名な「猫でもわかるプログラミング」シリーズのC#版です。

改訂3版が2016年02月27日に発売されました。

猫が理解できるかは置いといて、本当に初心者向けの内容から始まります。

コンピュータとは何かといった説明から始まり、コードは「Hello World」レベルから始まってます。

C#6の文法の説明まで含んでいるので一冊読み通せれば、C#の基本文法は一通り準ったことになります。

プログラムを始めてみたい方、C#の文法をざっくり俯瞰しなおしたい方、他言語から改宗希望の方などにお勧めです。

posted by RR at 15:38 | Comment(0) | 書籍 | このブログの読者になる | 更新情報をチェックする

マイクロソフト社がXamarin社を買収

2016年02月下旬、マイクロソフト社がXamarin社を買収したとのニュースがありました。

Xamarin社のサイトはこちら 

C#言語によるマルチプラットフォーム(クロスプラットフォーム)対応やモバイル対応をされている方にはお馴染みの会社です。

元々がMSとの関連の強い会社でしたが、MSが買収したそうです。買収額は公開されていませんが、300ミリオンドル以上との噂です。日本円で350億円ぐらいでしょうか。高いのか安いのか全然わかりません。

この買収については今後マイクロソフト側からいろいろ情報が出てくることと思います。

VS2015でも一部統合されていて(追加インストールが必要)、プロジェクトの新規作成メニューに出てきたりしますが、今後は完全統合されていくことになるでしょう。(きっと無料で)

今後のXamarinについて「勝手に予想」されていた記事がありました。

http://qiita.com/amay077/items/4aa25db9509216cf5bf0
posted by RR at 16:04 | Comment(0) | その他 | このブログの読者になる | 更新情報をチェックする

2016年03月14日

データの永続化 設定をどう保持するか

概要

データや設定などをプロセス終了後にも使用できるように、どう保存するかという問題
データベースなど他のプロセスやサービスを介する場合もあるが、ここではファイルへの保存を対象としてます

考慮事項

以下のような事項からどういったどう保存するのか検討していくことになる
  • 対象は何か
  • どのくらいの量か
  • 誰が使うか(自プログラムのみか)
  • ファイルの編集を許可するのか
  • 暗号化等の要否
  • 等々

どこに保存するか

保存形式により一意に決まるものもあるが、大体以下の場所が候補となる
  • アセンブリ内
  • 実行環境
  • 特殊フォルダ
  • 任意のフォルダ
以下はアプリケーションデータフォルダのパスを取得するサンプルコード
引数の列挙値とそれにより取得されるパスについてはMSDNを参照のこと

    string path = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

保存形式

INIファイル

拡張子がiniとなるテキストファイルでセクションとキーと値とから成る
大昔からあるが.NETでは非推奨で共通ライブラリにAPIもない
既存アプリや他アプリとの関係などのシガラミで使われることはある
using System.Runtime.InteropServices;
using System.Text;

    public class IniFileUtil
    {
        private string _path;

        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section,
            string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section,
                 string key, string def, StringBuilder retVal,
            int size, string filePath);

        // 引数のパスはファイルパス
        public IniFileUtil(string path)
        {
            _path = path;
        }

        public void IniWriteValue(string Section, string Key, string Value)
        {
            WritePrivateProfileString(Section, Key, Value, this._path);
        }

        public string IniReadValue(string Section, string Key)
        {
            StringBuilder sb = new StringBuilder(255);
            int i = GetPrivateProfileString(Section, Key, "", sb, 255, this._path);

            return sb.ToString();
        }
    }

レジストリ

レジストリとは、WindowsOSで使用される特殊なデータファイル
OS自体の設定もあるので編集に失敗するとWindows自体起動しなくなったりする
他のアプリ等に破損させられる可能性もあるとか肥大化しやすいとかデメリットあり
レジストリエディタを知らないと編集されずらいという利点もある
using Microsoft.Win32;
public class RegistryUtil
    {
        private string _path;

        // 引数のパスはレジストリのパス
        public RegistryUtil(string path)
        {
            _path = path;
        }

        public void Write(string key, object value)
        {
            using (var regkey = Registry.CurrentUser.CreateSubKey(_path))
            {
                regkey.SetValue(key, value);
            }
        }

        public object Read(string key)
        {
            using (var regkey = Registry.CurrentUser.OpenSubKey(_path, false))
            {
                if (regkey == null) return null;

                return regkey.GetValue(key);
            }
        }
    }

構成ファイルその1

構成ファイルとは、実行ファイルと同じフォルダに配置され、confingという拡張子が付くXMLファイル
プロジェクトに追加するとApp.configといったファイル名で登録されるが、ビルドすると実行環境には[ApplicationName].exe.configとリネームされ配置される
取得・編集用のメソッド等がいくつも提供されているが以下はそのうちの一つ
using System.Configuration;

    public class AppConfigUtil
    {
        public string Read(string key)
        {
            // プロセス起動時の値を保持しているので、編集処理がある場合は値を再取得する必要あり
            // ConfigurationManager.RefreshSection("appSettings");

            if (ConfigurationManager.AppSettings.AllKeys.Contains(key))
            {
                return ConfigurationManager.AppSettings[key];
            }

            return null;
        }

        public void Write(string key, string value)
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            if(config.AppSettings.Settings.AllKeys.Contains(key))
            {
                config.AppSettings.Settings[key].Value = value;
            }
            else
            {
                config.AppSettings.Settings.Add(key, value);
            }

            config.Save();
        }
    }

※デバック実行の場合、実行環境にある編集したファイルがビルド毎に上書きされるので要注意

構成ファイルその2

プロジェクトファイルのプロパティを選択し、プロパティ画面の「設定」タブに名前・型・スコープ・値を設定することができます
設定は構成ファイルに保持され、アクセス用のコードが自動生成されます

以下は名前:SampleString、型:String、スコープ:ユーザーで作成した設定の取得・変更用サンプル
    public class SettingUtil
    {
        public string GetSampleString()
        {
            return Properties.Settings.Default.SampleString;
        }

        public void SetSampleString(string value)
        {
            Properties.Settings.Default.SampleString = value;
            Properties.Settings.Default.Save();
        }
    }

リソースファイル

プロジェクトに「新しい項目の追加」⇒「リソースファイル」で拡張子resxというファイルが追加されます
プロパティ画面の設定タブと同様に設定を追加し取得することが可能です
値はハードコードされアセンブリ内に保持されます。編集保存はできません
    public class ResourceFileUtil
    {
        public string GetSampleString()
        {
            return Properties.Resources.SampleString;
        }
    }

シリアライズ

オブジェクトをそのままファイルに保存できるし復元できるので便利
使用するシリアライザーによってはファイルサイズが大きくなる

以下はXML形式でシリアライズするサンプル
using System.IO;
using System.Xml.Serialization;
    public class XmlSerializeUtil
    {
        private string _path;

        // 引数のパスは保存ファイル
        public XmlSerializeUtil(string path)
        {
            _path = path;
        }

        // 復元(デシリアライズ)する際に型を指定する
        public T Read<T>()
        {
            var serializer = new XmlSerializer(typeof(T));

            using (var reader = new StreamReader(_path))
            {
                return (T)serializer.Deserialize(reader);
            }
        }

        public void Write<T>(T obj)
        {
            var serializer = new XmlSerializer(typeof(T));

            using (var writer = new StreamWriter(_path,false,Encoding.UTF8))
            {
                serializer.Serialize(writer, obj);
            }
        }
    }


テキストファイル

場合よってはプレーンのテキストファイルが一番だったりする
    public class TextFileUtil
    {
        private string _path;

        // 引数のパスは保存ファイル
        public TextFileUtil(string path)
        {
            _path = path;
        }

        public string Read()
        {
            return File.Exists(_path) ? File.ReadAllText(_path) : string.Empty;
        }

        public void Write(string value)
        {
            File.WriteAllText(_path, value);
        }
    }

SQLite

ファイルへのアクセスを標準SQLで実行できる無料のライブラリ
保存対象のデータが大量にある場合などで有効
別途記載(予定)

その他


・複数のプロセスが同時に編集する可能性がある場合は排他処理の考慮が必要
・勝手に編集されたくない場合、隠しファイル(Hiden属性を付与)すると有効だったりする
・暗号化するのが正解だったりするんですが

posted by RR at 22:35 | Comment(0) | Tips | このブログの読者になる | 更新情報をチェックする

2016年03月16日

配列の最大要素数は2^31ではない

配列の添字(Index)はint型なので、その最大値が取れるかと試してみると失敗する。
     var array = new int[int.MaxValue];
上記コードはOutOfMemoryExceptionがスローされる。

その閾値はいくつなのかと調べてみたらMSDNにありました。

https://msdn.microsoft.com/ja-jp/library/system.array.aspx

引用します。(日本語訳はないみたい)
By default, the maximum size of an T:System.Array is 2 gigabytes (GB). In a 64-bit environment, you can avoid the size restriction by setting the enabled attribute of the configuration element to true in the run-time environment. However, the array will still be limited to a total of 4 billion elements, and to a maximum index of 0X7FEFFFFF in any given dimension.

デフォルトの設定では、オブジェクトの最大サイズは2ギガバイトです。64ビット環境の場合、構成ファイルの設定により実行時のこの制限を解除することができます。但し、合計要素数40億の制限はそのままですし、インデックス(添字)の最大数である0X7FEFFFFF(約21億)の制限もそのままです。

つまり、以下の条件を満たす値ということらしい。

・インデックスであるint.MaxValueより小さい
・オブジェクトのサイズが2Gより小さい
・合計要素数(多次元配列等でも)が40億より小さい
(・実行時のヒープに連続使用可能領域がある?)

同一マシンでなんどか試行してみても閾値一致しないし、同一スペックのマシンで試行してもかなり幅がありました。よくわかりません、すいません。

とりあえずInt.MaxValueなんて一度も取れませんでした。
posted by RR at 02:22 | Comment(0) | 集合 | このブログの読者になる | 更新情報をチェックする