HUSKING - kotteri

技術系Note

Amazonアソシエイト

ブログ始めて1週間経ったところでAmazonアソシエイトに申し込んで、
無事審査に合格しました

  • 記事は20くらい
  • 日々のアクセスはほぼ0

・・・多分、長年アマゾンプライム会員だったからかな。。



運用方法はオーソドックスに

  • オススメ商品は記事内


でとりあえずやってみます。。てかそれ以外思いつきません。。

【C#】DataContractJsonSerializerでJSONを扱う

使用するための準備

1. シリアライズ(Object > JSON)用メソッドを作成

using System.IO; // ←追加
using System.Runtime.Serialization.Json; // ←追加
 
namespace JsonTestApp
{
    public static class JsonUtils
    {
        /// <summary>
        /// オブジェクトからJSONへ変換します
        /// </summary>
        /// <param name="obj">JSONへ変換するオブジェクト</param>
        /// <returns>JSON</returns>
        public static string ToJson(object obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                var serializer = new DataContractJsonSerializer(obj.GetType());
                serializer.WriteObject(ms, obj);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }
    }
}


2. デシリアライズJSON > Object)用メソッドを作成

using System.IO; // ←追加
using System.Runtime.Serialization.Json; // ←追加
 
namespace JsonTestApp
{
    public static class JsonUtils
    {
        /// <summary>
        /// JSONからオブジェクトへ変換します
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json">オブジェクトへ変換するJSON</param>
        /// <returns>オブジェクト</returns>
        public static T ToObject<T>(string json)
        {
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                var serializer = new DataContractJsonSerializer(typeof(T));
                return (T)serializer.ReadObject(ms);
            }
        }
    }
}

実際の使用例

1. JSONへ変換するためのオブジェクトを作成

using System.Runtime.Serialization; // ←追加
 
namespace JsonTestApp
{
    [DataContract] // ←重要
    class SampleData
    {
        [DataMember] // ←重要
        public string name { get; set; }
        
        [DataMember] // ←重要
        public string age { get; set; }
    }
}


2. Object から JSON

static void Main(string[] args)
{
    SampleData data = new SampleData();
    data.name = "大泉 洋";
    data.age = "44歳";
    string json = JsonUtils.ToJson(data);
    Console.WriteLine(json);
}

コンソール出力結果

"{\"age\":\"44歳\",\"name\":\"大泉 洋\"}"


3. JSONからObjectへ

static void Main(string[] args)
{
    string json = "{\"age\":\"44歳\",\"name\":\"大泉 洋\"}";
    SampleData data = JsonUtils.ToObject<SampleData>(json);
    Console.WriteLine(data.name);
    Console.WriteLine(data.age);
}

コンソール出力結果

大泉 洋
44歳

【XAMARIN】ピッカーの初期値

ピッカーの初期値を設定したくて悩んだ話



まず、以下のようにピッカーを準備

XAML
<Picker x:Name="picker" ItemDisplayBinding="{Binding Key}"/>
C#

ピッカー用のモデルクラス

using System;
namespace SimpleMemo
{
    public class PickerModel
    {
        public int Id { get; set; }
        public string Key { get; set; }
    }
}

ピッカーの中身を設定

// ピッカー用のリスト
ObservableCollection<PickerModel> Lists = new ObservableCollection<PickerModel>();

// ピッカーの中身をDBから取得
foreach (var row in db.Table<CategoryTable>().OrderBy(X => X.Id).ToList())
{
    Lists.Add(new PickerModel
    {
        Id = row.Id,
        Key = row.Key
    });
}

// ピッカーソース設定
this.picker.ItemsSource = this.Lists;

で、画面表示時にピッカーの初期値を設定したくて、悩んだ結果、以下のようにしました。

// ピッカー用のリストから、Id = 2のもののIndexを取得
var idx = this.Lists.Select((item, index) => 
    new { Index = index, Value = item })
    .Where(item => item.Value.Id == 2)
    .Select(item => item.Index);

// ピッカーの初期インデックスを設定
this.picker.SelectedIndex = idx.Single();


他に良い方法があれば、教えてください。。

【XAMARIN】SQLiteを試す

データの永続的な保存方法として、SQLiteを使用してみた。

<注意>自分は今回以下のように使用しただけで、本当に使い方が合ってるかは分かりかねます


使用準備

NuGetから「sqlite-net-pcl」をインポートするだけ

テーブル用のクラスを作成

using System;
namespace SimpleMemo
{
    public class CategoryTable
    {
        [SQLite.PrimaryKey, SQLite.AutoIncrement]
        public int Id { get; set; }
        public string Key { get; set; }
    }
}

CategoryTable というテーブルを作成。
[Id]というカラムをプライマリキーにし、自動採番するようにしてます。

SELECT

string database = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "SimpleMemo.db");

using (var db = new SQLite.SQLiteConnection(database)
{
    // テーブル作成(何度呼び出しても問題なし。すでに作成されている場合はCreateTableは走らないらしい)
    db.CreateTable<CategoryTable>();

    // カテゴリテーブルのデータを全て取得(ID順)
    List<CategoryTable> row = db.Table<CategoryTable>().OrderBy(x => x.Id).ToList();
}

C#だとLinqが使えて凄く便利!

UPDATE

using (var db = new SQLite.SQLiteConnection(database)
{
    // Id = 1のレコードを取得
    CategoryTable row = db.Table<CategoryTable>().SingleOrDefault(x => x.Id == 1);

    // 更新
    if (row != null)
    {
        row.Key = "ざまりん";
        db.Update(row);
    }
}

直にUPDATE文を書いた方がSQL一回で済むし、処理的には速そう

DELETE

using (var db = new SQLite.SQLiteConnection(database)
{
    // Id = 1のレコードを取得
    CategoryTable row = db.Table<CategoryTable>().SingleOrDefault(x => x.Id == 1);

    // 削除
    if (row != null)
    {
        db.Delete<CategoryTable>(row.Id);
    }
}

このやり方が良いのかは凄く微妙・・・

INSERT

using (var db = new SQLite.SQLiteConnection(database)
{
    // 追加
    db.Insert(new CategoryTable
    {
        Key = "ざまりん"
    });
}


ここで凄く悩んだことが一つ!!
INSERTで自動採番したIDを取得したいと思ったのですが、良い方法が見つからず。。。
結局、INSERT後に、以下のSQLを実行して取得してます。

// 一番新しい行を取得
CategoryTable lastData = db.Query<CategoryTable>("SELECT * FROM CategoryTable ORDER BY rowid desc limit 1").Single();

// ID取得
int id = lastData.Id;

もっと良い方法があるはず!!
どなたか教えていただけると嬉しいです。。。

【XAMARIN】Admob広告を表示

Xamarinを試してみるに、初めにAdmobの広告を試してみた。


実装方法は以下の方の記事が凄く参考になると思います。
qiita.com


手を入れたのは、iOSAndroidのそれぞれのカスタムレンダラー。
Admobは自分で広告をクリックするとダメらしいので、
自分の端末をテスト端末として登録。

iOS
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Google.MobileAds;
using UIKit;
using CoreGraphics;
using SimpleMemo;
using SimpleMemo.iOS;

[assembly: ExportRenderer(typeof(AdMobBanner), typeof(AdMobBannerRenderer))]
namespace SimpleMemo.iOS
{
    public class AdMobBannerRenderer : ViewRenderer
    {
        private const string adUnitID = @"ca-app-pub-*********************";  // ← Admobで作成した広告ID
        private bool onScreen;

        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
            {
                return;
            }

            if (e.OldElement == null)
            {
                UIViewController viewController = null;
                foreach (UIWindow window in UIApplication.SharedApplication.Windows)
                {
                    if (window.RootViewController != null)
                    {
                        viewController = window.RootViewController;
                        break;
                    }
                }

                if (viewController == null)
                {
                    viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
                }

                var banner = new BannerView(AdSizeCons.Banner, new CGPoint(-10, 0))
                {
                    AdUnitID = adUnitID,
                    RootViewController = viewController
                };

                banner.AdReceived += (sender, args) =>
                {
                    if (!onScreen)
                    {
                        AddSubview(banner);
                        onScreen = true;
                    }
                };
                var request = Request.GetDefaultRequest();
                request.TestDevices = new string[] { "*******************" }; // ← テスト端末のID
                banner.LoadRequest(request);
                SetNativeControl(banner);
            }
        }
    }
}
Android
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using SimpleMemo;
using SimpleMemo.Droid;

[assembly: ExportRenderer(typeof(AdMobBanner), typeof(AdMobBannerRenderer))]
namespace SimpleMemo.Droid
{
    public class AdMobBannerRenderer : ViewRenderer<AdMobBanner, Android.Gms.Ads.AdView>
    {
        private const string adUnitID = @"ca-app-pub-******************"; // ← Admobで作成した広告ID

        protected override void OnElementChanged(ElementChangedEventArgs<AdMobBanner> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
            {
                var banner = new Android.Gms.Ads.AdView(Forms.Context);
                banner.AdSize = Android.Gms.Ads.AdSize.Banner;
                banner.AdUnitId = adUnitID;

                var builder = new Android.Gms.Ads.AdRequest.Builder();
                builder.AddTestDevice("**************"); // ← テスト端末のID
                banner.LoadAd(builder.Build());
                SetNativeControl(banner);
            }
        }
    }
}


最後に、ちょっと困った?こと

最初、上記を実装しても全然広告が出ませんでした。
コンソールを見ると以下のような出力が。。。

There was a problem getting an ad response. ErrorCode: 0 Failed to load ad:0

これじゃ意味わからん!って困ってたのですが、単純なミスに気づく。。


Admobのアカウントを作成しただけで満足してて、必要なアカウント情報を入力してなかった・・・


アカウント情報を入力して、承認のメールが届いたら、表示されるようになりました。

以下、アカウントが承認された状態
f:id:huskworks53:20180720220502p:plain:w300

ここが最初、「まだ完了してません」みたいなメッセージが出てました。。

【C#】インスタンスの動的生成(Type.Invokember)

※ TestClassというクラスは事前に作成しておく。

文字列からインスタンスを生成(動的にインスタンスを生成するのに便利)
string[] weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    
// NameSpaceという名前空間のTestClassのインスタンスを生成(コンストラクタの引数にweekDaysを指定)
Type t = Type.GetType("NameSpace.TestClass");
var inst = (TestClass)t.InvokeMember(null, System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { weekDays });
インスタンスを指定してメソッドを実行(クラス違いの同名メソッドを実行するのに便利)
string[] weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    
// TestClassのexecuteというメソッドを実行(メソッドの引数にweekDaysを指定)
TestClass inst = new TestClass();
Type t = inst.GetType();
t.InvokeMember("execute", System.Reflection.BindingFlags.InvokeMethod, null, inst, new object[] { weekDays });

【C#】Windowsでの tail -f 的なことをしたかった

ので、簡易的なものを作ってみた

string file = "c:\aaa.txt";
FileInfo fi = new FileInfo(file);
if (!fi.Exists)
{
    Console.WriteLine(string.Format("指定されたファイル({0})が存在しません", file));
}
using (FileStream fs = fi.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    bool run = true;
    // リードポインタをファイル最後尾にもってくる
    fs.Position = fs.Length;
    using (FileSystemWatcher fw = new FileSystemWatcher())
    {
        // 監視するフォルダ
        fw.Path = fi.DirectoryName;
        // 監視フィルタ設定
        fw.Filter = fi.Name;
        // 出力イベント用メソッド
        Action<Object, FileSystemEventArgs> ReadText = (sender, e) =>
        {
            fi.Refresh();
            // ファイルの追加分を読み込む
            long diff = fs.Length - fs.Position;
            if (diff < 1)
            {
                return;
            }
            byte[] bytes = new byte[diff];
            fs.Read(bytes, 0, bytes.Length);
            // 読み込んだ文字列を行区切りに分割する
            string[] lines = Encoding.GetEncoding("utf-8").GetString(bytes).Split('\n');
            // コンソールに出力
            foreach (string line in lines)
            {
                if (!line.Equals("\r"))
                {
                    Console.WriteLine(line);
                }
            }
        };
        // 停止イベント用メソッド
        Action<Object, ConsoleCancelEventArgs> EventStop = (sender, e) =>
        {
            // ウォッチ停止
            fw.EnableRaisingEvents = false;
        };
        // ctrl + c 時処理
        Console.CancelKeyPress += new ConsoleCancelEventHandler(EventStop);
        // イベント検出時処理
        fw.Changed += new FileSystemEventHandler(ReadText);
        // ウォッチ開始
        fw.EnableRaisingEvents = true;
        // ループ処理
        while (run)
        {
            string input = Console.ReadLine();
            if (!string.IsNullOrEmpty(input) && input.Equals("quit"))
            {
                fw.EnableRaisingEvents = false;
                run = false;
            }
        }
    }
}
Console.WriteLine("\n\nStopped...");

aaa.txtに行が追加されると、自動でコンソールに出力される。
終了する場合には、"quit"と入力する。