20210908のC#に関する記事は8件です。

上手なクラス分けをするために頑張ることをまとめてみた。

先月8月から受託系IT企業で働き始めました。 一旦は社内業務ということで、開発言語C#にて勉強を進めているのですが早速クラスという壁にぶち当たりました。 まずクラスとは? ++C++;というサイトによると、 操作の対象となるものをオブジェクトといいます。 オブジェクトを作る場合、まず設計図が必要になります。 内部がどういう構造になっているのか、外部からどのような操作をすることが出来るのかを決めてやるわけです。 このようなオブジェクトの設計図のことをクラス(class)といいます。 とのこと。 私なりの解釈として、「ロールキャベツを作る」という目的(オブジェクト)に対して「食材を用意する」「切る」「煮る」というように役割(クラス)を分けてあげるようなものかな、という答えに行きつきました。 確かに分けたほうが分かりやすい。私個人だけではなく、色んな人と共有しながらでも使いやすい。また、仕様変更になった場合も少ない作業量での変更対応がしやすい。 とりあえず様々なメリットがあることが分かりました。 どういう基準でクラス分けをするのだろう それでは実装してみようということなり、VisualStudioを立ち上げてみましたがすぐに疑問が出てきました。 1つのクラスに対してどこまで機能を持たせたらいいのだろう、、、 調べてみても私の中で分かりやすい説明を見つけられず、会社の方にも聞いてみたのですが、難しい話らしくこれといった明確な答えは出なかったように思えます。 私の中でイメージしやすいなと思ったのは、「これは◯○という役割を持ったクラスです」と簡潔に説明できるようにする、ということ。 上記のロールキャベツの例でいくと、「食材を用意するクラスでは、ロールキャベツに必要な食材を全てまとめて並べます。」「切るクラスでは、大きい食材から順番に同じ大きさに切ります。」というようなイメージかなと思いました。 これから意識すること なんとなくイメージはできたので、実際にシステムやアプリケーションを作る際に上手なクラス分けをするために以下のようなことを意識、挑戦してみます。 ・とにかくコードを書く。 汚いコードでも、クラス分けが違っていても、自分の考えや実現させたいことをコードで表せるようにする。 たくさんコードを書く中で、上手くクラスを分けられることもあれば、分けられていない時も出てくるので次書く時に何をどう改善したらいいかを学習する。 ・コードを書く際に本を読みつつ理解を深めながら書いてみる。 がむしゃらにコードを書くのもどうかな、と思うし早くコードを書くのに慣れたいのでインプットもしつつ。 今のところはC#で住所録を作ろうかなと考えているのですが、他に何か良さそうな課題が思いつけば着手していこうと思います。 私の理解が甘かったり認識が違うかもしれないですが、とりあえずの現状整理と目標をまとめてみました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity スクリプトの実行順番をコントロールする方法

0.0 はじめに Unityでは異なるスクリプト間でのAwake/Startメッソドの実行順序は原則不規則です。この順番を制御する方法があります。 下記のどちらかで制御が可能です。 1.0 [DefaultExecutionOrder()]属性をつかう 下のように[DefaultExecutionOrder()]属性をクラス(スクリプト)につけます。()内に数字をいれます。小さな数字から実行されます。0がデフォルトなので先に実行させるためにマイナスの数字をいれると良いでしょう。 Test.cs [DefaultExecutionOrder(-5)] public class Test : MonoBehaviour{ } 2.0 Script Execution Orderをつかう メニューで Edit --> Project Settings(Unity2018.4)を選びます。 『Script Execution Order』を選択します。 ウィンドウでの設定はシンプルで、[+]を押してスクリプトを追加し、スクリプトを実行したい順に並べるだけです。数字が小さなものから(上から順に)実行されます。全てのスクリプトを指定する必要はありません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】文字列を0や空白で埋める

コード 文字列の場合 string str = Console.ReadLine(); //試しに1と入力 Console.WriteLine(str.PadLeft(3, '0')); //001 Console.WriteLine("{0,3:d}", str); //001 //空白を挿入する場合 Console.WriteLine(str.PadLeft(3, ' ')); // 1 //入力した文字数を含めた分の空白を入れる。この場合は空白2つ。 String.PadLeft()は左側から順番に指定した文字数になるまで埋めていく。 String.PadRight()はその逆。 数値の場合 int N = int.Parse(Console.ReadLine()); //1を入力 Console.WriteLine(N.ToString("d3")); //001 Console.WriteLine(string.Format("{0:d3}", N)); //001 //逆に0詰めをする場合 Console.WriteLine(string.Format("{0,-3:d}a", N)); //1 a //入力した文字数を含めた分の空白を入れる。この場合は空白2つ。 表示方法1つを取っても、様々な表し方があるのが面白いです。 ふと気になったのですが、 詰めるときのコードで表記している「d」は何の略語なんでしょうか…。 個人的には桁を意味するdigitの頭文字なのかな?と勝手に思っています。 何かを覚えるときは、意味を関連付けたほうが断然覚えやすいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラスをコマンドライン化する。

適当にクラスを作って CmdLine<T> に加える。 public class xyz{ void random(string x){...} } var x=new CmdLine<xyz>(); //全てawait化される。 await x.cmdline("random 100"); //x.cmdline("関数名 引数1 引数2"); public class CmdLine<T> where T : new() { T obj = new(); Type objType = typeof(T); char sep = ' '; public async Task<dynamic> cmdline(string str) { var ary = str.Split(sep); var cmd = ary.First(); var fn = objType.GetMethod(cmd); if (fn == null) return false; var max = fn.GetParameters().Length; var args = Enumerable.Repeat("", max).ToArray();//引数分用意 var _args = ary.Skip(1).Take(max).ToArray(); for (var i = 0; i < _args.Length; i++) args[i] = _args[i]; return await fn.InvokeAsync(obj, args); } }//class CmdLine 全部 using System; using System.Reflection; using System.Threading.Tasks; using System.Linq; namespace Invoker { public static class MethodExtension { public static async Task<dynamic> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters) { //あらゆる関数をタスク化する。 dynamic awaitable = @this.Invoke(obj, parameters); if (isNonTask(@this) && awaitable != null) return awaitable; if (isNonTask(@this)) return true; await awaitable; if (isVoidTask(@this)) return true; return awaitable.GetAwaiter().GetResult(); } static bool isNonTask(MethodInfo m) { var ch = typeof(Task).ToString(); if (m.ReturnType.ToString().IndexOf(ch) == -1) return true; return false; } static bool isVoidTask(MethodInfo m) { var ch = typeof(Task).ToString(); if (m.ReturnType.ToString() == ch) return true; return false; } } public static class StringExtension{ public static int ToInt(this string @this,int falseValue=-1){ var d = @this.ToDecimal((decimal) falseValue); return (int)d; } public static float ToFloat(this string @this, float falseValue = -1) { var d = @this.ToDecimal((decimal)falseValue); return (float)d; } public static bool ToBool(this string @this, bool falseValue=false) { var wk = falseValue==true?1:0; var d = (int)@this.ToDecimal((decimal)wk); return (d==1)?true:false; } public static decimal ToDecimal(this string @this,decimal falseValue=-1){ if (decimal.TryParse(@this, out decimal ret)) return ret; else return falseValue; } } public class CmdLine<T> where T : new() { T obj = new(); Type objType = typeof(T); char sep = ' '; public async Task<dynamic> cmdline(string str) { var ary = str.Split(sep); var cmd = ary.First(); var fn = objType.GetMethod(cmd); if (fn == null) return false; var max = fn.GetParameters().Length; var args = Enumerable.Repeat("", max).ToArray();//引数分用意 var _args = ary.Skip(1).Take(max).ToArray(); for (var i = 0; i < _args.Length; i++) args[i] = _args[i]; return await fn.InvokeAsync(obj, args); } }//class CmdLine }// namespace program { using Invoker; public class wrapper{ public void random(string x){ //文字列から受け取るため引数は文字列のみ。 //random 100 var r=new Random(); var ret=x.ToInt(10); ret=r.Next(0,ret); Console.WriteLine(ret); } public async Task wait(string time){ //wait 100 var ret =time.ToInt(0); await Task.Delay(ret); } public async Task<int> sum(string a,string b){ //sum 100 99 var _a=a.ToInt(0); var _b=b.ToInt(0); await wait(""+1000); return _a+_b; } public void dummy(){ //dummy Console.WriteLine("dummy"); } }//class class Program { static async Task Main(string[] args) { var x=new CmdLine<wrapper>(); await x.cmdline("random 100"); await x.cmdline("random");//less args await x.cmdline("random 100 100 999 111");//too much args await x.cmdline("wait 1000"); var ret=await x.cmdline("sum 100 99"); int t = ret + 5; await x.cmdline("dummy aaa"); await x.cmdline("dummyxyz");//notfound method Console.WriteLine("Hello World!"); } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity で、気軽に呼び出せるダイアログを作る

Unity で、気軽に呼び出せるダイアログを作る。 Unity でダイアログを作る方法はすでにいろいろ紹介されていますが、ここでは「気軽に呼び出せる」をコンセプトにしたダイアログを作ってみます。 気軽に呼び出せるとは、「Debug.Log」とか、JavaScript の alert のように使え、ヒエラルキーにオブジェクトを置いておく必要もなく、従って、Scene を気にせずにどこからでも呼び出せるものを目指します。 仕様 ダイアログの呼び出し方は、とりあえず以下の3種類を用意します。 /* メッセージとOKボタンを出し、OKボタンを押すと消える */ MyDialog.Alert("メッセージ"); /* メッセージとOKボタンを出し、OKボタンを押すと指定した処理を実行する */ MyDialog.Alert("メッセージ", Click_OK); /* メッセージとOKボタンとCanselを出し、ボタンを押すと指定した処理を実行する */ MyDialog.Confirm("メッセージ", Click_OK, Click_Cancel); /* 上記呼び出しで呼び出されるAction */ void Click_OK() { ... なんらかの処理 } void Click_Cancel() { ... なんらかの処理 } Unity 2020.2.1f1 と、2019.3.15f1 で動作確認しました。 実装方法 上記のように呼び出せるようにするため、スクリプトは MonoBehaviour を継承せず、スクリプト内部で GameObjectを生成するようにします。これは、まずは GameObject を用意してスクリプトをアタッチするUnityでの一般的な作りとは、反対方向のアプローチになります。 ただし、Canvas と EventSystem までスクリプトで用意するのは面倒なので、この2つだけはヒエラルキーで作って下さい。ダイアログを表示したい全ての Scene で、Canvas と EventSystem を用意しておく必要があります。 ヒエラルキーに Canvas と EventSystem を作るには、UI - Button などを作成してから削除するのが楽です。 本当に何も考えずにスクリプトだけで GameObject を作ると、フォントサイズとかのプロパティを全てスクリプトで指定することになって面倒なため、プレハブを使います。 ダイアログ(Panel)自身と、その中に表示する文字、ボタンも、全てプレハブで作ります。 これは「prefab in prefab」という状態になり、後で説明しますが、ちょっとしたコツが必要です。 部品を全てプレハブとすることで、画像付きのダイアログなども簡単に拡張可能になります。 部品をプレハブにする関係で、下記の説明では部品に名前を設定しています。 サンプル通りの名前にしなかった場合は、スクリプトの該当箇所を修正してください。 プレハブと設定 1. ダイアログ Panel ダイアログそのものは、UI - Panel で作ります。 このパネルの中にテキストなどの部品を加えていき、部品の大きさによってダイアログの大きさも変化するように設定します。 UI → Panel を作成。名前は「DialogPanel」 表示したい Width を設定。この Width が最終的な見た目に影響します。 デフォルト設定では Image の Color のアルファ(「A」の値)が 100 ですが、このパネルを背景色とするため、A を最大値の 255 にしておきます。 Add Component で、Layout → Contentet Size Fitter 「Contentet Size Fitter」の Vertical Fit を「Preferrer Size」に Add Component で、 Layout → Vertical Layout Group 「Vertical Layout Group」の 「Control Child Size」→「Height」にチェックを入れます。 この設定で、部品の Height に応じて「DialogPanel」の Height も変わるようになります。 「Vertical Layout Group」の Padding に適当な値を入れておきます。デフォルトの 0 のままだと、メッセージがパネルの外側にひっついてしまいます。Spacing も設定し、オブジェクト間に隙間を持たせます。 この DialogPanel の Width から「Padding - Left」と「Padding - Right」を引いた値を、DialogPanel 内の部品 Width に使います。以下の説明を簡単にするため、この値を「コンテンツ Width」と表現することにします。 2. ダイアログ内の部品 この「DialogPanel」の中に部品を追加します。 (ヒエラルキーで「DialogPanel」を選択してから、右クリックの「UI」で部品を追加します) テキスト テキストもプレハブ化することにします。 プレハブ部品にしておくことで、後で画像付きダイアログを追加したいときとかの対応が柔軟になります。 「DialogPanel」の中に、UI → Text を作成。名前は「DailogText」とします。 「DailogText」の Width は、上で説明した「コンテンツ Width」にする。 適当にフォントサイズや行間などを設定してください(何かダミーのテキストをセットすると、調整しやすいです)。 OK ボタン まず Panel を作り、その中に Button を配置します。Panel が無いと、Button が左端に寄ってしまいます。 「DialogPanel」の中に、UI → Panel を作成。名前は「OkPanel」。 「OkPanel」の Width を「コンテンツ Width」に。 Image の Source Image は「None」に、Color の A は 0 に。 「Raycast Target」のチェックボックスを OFF にしておく。 ついでに「Maskable」も OFF にして良いと思います。 「OkPanel」の中に、UI → Button を作成。名前は「OkButton」。 Button の中の Text の文字列を「OK」に。フォントサイズを調整。フォントサイズに応じて Button の Width・Height も調整。 ここで、「OkPanel」の「Raycast Target」を OFF にするのが、超重要です。 普通はヒエラルキーの下にあるものが上に表示され、当たり判定も下にあるものが先になりますが、「prefab in prefab」で加えた部品は、親の当たり判定が子より優先されるようなのです。子は親よりヒエラルキーの下に表示されるので、一般的なヒエラルキーの感覚とは逆になります。 このため、OkPanelの「Raycast Target」が ON(デフォルト) のままだと、Panel の中にある Button が反応しなくなります。 この挙動を説明しているドキュメントが無く、原因を追及するのにかなり苦労しました。 OK・Cancel ボタン OKボタンと同じように、OK・Cancel ボタンを作ります。 「OkPanel」を Duplicate して作るのが楽です。 ヒエラルキー上の「OkPanel」を右クリックして Duplicate し、名前を「OkCancelPanel」に変更します。 「OkCancelPanel」の中の「OkButton」も Duplicate し、名前を「CancelButton」に変更します。 「OkButton」と「CancelButton」の Pos X を変更して2つのボタンを横に並べます。 「CancelButton」の中の Text の文字列を「Cancel」に プレハブ化 以上ができたら、全体的なサイズや Padding 値などを調整します。 こんな感じになりましたでしょうか? 調整が終わったらプレハブ化をおこないます。 プレハブ化の手順は以下の通りです。 ヒエラルキーを Load するためには Resources フォルダが必要なので、無ければ作ります。 Resources の下に「Dialog」という専用フォルダを作ります。 ダイアログで使用する全てのプレハブとスクリプトを1つのフォルダーにまとめておくと、Asset → Export で unitypackage ファイルにすることが出来、他のプロジェクトに Import しやすくなるのでお勧めです。 ヒエラルキーから「DailogText」「DialogOk」「DialogOkCancel」の3つをそれぞれ Projectの「Dialog」にドラッグしてプレハブ化します。プレハブ化したら(表示が青色になったら)ヒエラルキーで右クリックして Delete します。 「DialogPanel」をプレハブ化し、ヒエラルキーから Delete。 ここでは4つのプレハブを作るのが目的で、ダイアログがヒエラルキーに依存しなくて良いようにするために、ヒエラルキーからは削除しておくのです。 作られたプレハブは、Contentet Size Fitter の中にあったため、Height が 0 になっています。 そのままでは変更がしにくいので、Height に適当な値を設定した方が良いでしょう。 スクリプトから実際に Instantiate すると、Height は元通り無視されます。 と、ここまで書いておいてナニですが、プレハブを作るのが面倒くさいと思う方のために、unitypackage をココからダウンロードできるようにしておきました。 これを使って自分流にカスタマイズするのが楽だと思います。 スクリプト 「Dialog」フォルダ内に C# Scriptを作成し、名前を「MyDialog」とします。 この「MyDialog」をエディタで編集して下記のものに書き換えます。 ダイアログを呼び出す度にプレハブを Load するのは気が引ける(?)ので、全体をシングルトンにしてみました。 また、上述のように MonoBehaviour は継承していないので、プレハブを Instantiate する時にちょっと面倒な指定が必要です。メソッドを参考にしてください。 using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /** <summary> 気軽に呼び出せるダイアログ </summary> */ public class MyDialog { private static MyDialog m_Instance = null; Transform CanvasTr; // ヒエラルキー上にある Canvas の Transform GameObject DialogPanel; // ダイアログ外観 Dictionary<string, GameObject> LoadedPF; // Loadした全プレハブ部品 Action ActionOK = null; // OKボタンが押された時の処理 Action ActionCancel = null; // Cancelボタンが押された時の処理 /// <summary> /// シングルトンの為のインスタンス /// </summary> private static MyDialog Instance { get { if (m_Instance == null) { m_Instance = new MyDialog(); } return m_Instance; } } /// <summary> /// コンストラクタ /// </summary> private MyDialog() { CanvasTr = GameObject.Find("Canvas").transform; // Canvas だけは、ヒエラルキーから拾う LoadedPF = new Dictionary<string, GameObject>(); // プレハブ保持用の連想配列 } /// <summary> /// メッセージをダイアログで表示して「OK」ボタンで待つ /// </summary> /// <param name="mess">表示するメッセージ</param> /// <param name="funcOk">「OK」ボタンが押された時の処理</param> static public void Alert(string mess, Action funcOk = null) { MyDialog dialog = Instance; dialog.DialogPanel = dialog.Instantiate("DialogPanel"); // ダイアログ外観 dialog.AddObj("DialogText").GetComponent<Text>().text = mess; // メッセージ dialog.ActionOK = funcOk; dialog.AddObj("OkPanel").transform.Find("OkButton").GetComponent<Button>().onClick.AddListener(dialog.ClickOkButton); } /// <summary> /// OK / Cancel 確認ダイアログを表示する /// </summary> /// <param name="mess">表示するメッセージ</param> /// <param name="funcOk">「OK」ボタンが押された時の処理</param> /// <param name="funcCancel">「Cancel」ボタンが押された時の処理</param> static public void Confirm(string mess, Action funcOk = null, Action funcCancel = null) { MyDialog dialog = Instance; dialog.DialogPanel = dialog.Instantiate("DialogPanel"); dialog.AddObj("DialogText").GetComponent<Text>().text = mess; dialog.ActionOK = funcOk; dialog.ActionCancel = funcCancel; GameObject buttonPanel = dialog.AddObj("OkCancelPanel"); buttonPanel.transform.Find("OkButton").GetComponent<Button>().onClick.AddListener(dialog.ClickOkButton); buttonPanel.transform.Find("CancelButton").GetComponent<Button>().onClick.AddListener(dialog.ClickCancelButton); } /// <summary> /// OKボタンが押された時の処理 /// </summary> private void ClickOkButton() { Close(); // ダイアログを消す if (ActionOK != null) { // コールバック先が登録されていれば ActionOK(); // 実行 } } /// <summary> /// Cancelボタンが押された時の処理 /// </summary> private void ClickCancelButton() { Close(); // ダイアログを消す if (ActionCancel != null) { ActionCancel(); } } /// <summary> /// 非MonoBehaviour 用の、プレハブ Instantiate(実体化) /// </summary> /// <param name="prefabName">Instantiate したいプレハブ名</param> /// <returns>生成された GameObject</param> private GameObject Instantiate(string prefabName) { if (!LoadedPF.ContainsKey(prefabName)) { // まだプレハブが Load されていなければ LoadedPF.Add(prefabName, (GameObject)Resources.Load("Dialog/" + prefabName)); // Load } GameObject obj = UnityEngine.Object.Instantiate(LoadedPF[prefabName]); obj.transform.SetParent(CanvasTr, false); obj.transform.localScale = Vector3.one; obj.GetComponent<RectTransform>().anchoredPosition3D = Vector3.zero; // anchoredPosition3D をセットしないと、Pos.Z が不定になる。 return obj; } /// <summary> /// DialogPanel に GameObject 追加 /// </summary> /// <param name="add">追加する部品名</param> /// <returns>追加された GameObject</param> private GameObject AddObj(string add) { GameObject obj = Instantiate(add); obj.transform.SetParent(DialogPanel.transform, false); return obj; } /// <summary> /// ダイアログを閉じる /// </summary> private void Close() { foreach (Transform child in DialogPanel.transform) { // 追加した GameObject を削除 UnityEngine.Object.Destroy(child.gameObject); } UnityEngine.Object.Destroy(DialogPanel); // ダイアログパネルを消す } } まとめ 「気軽に呼び出せる」ことと拡張が容易なことにこだわったのでスクリプトは長くなりましたが、使い勝手はかなり良いと思います。自分が過去に作ったプロジェクトも、このダイアログを使ってリファクタリングしたくなりました。 「Raycast Target」は、このダイアログの例では、DialogPanel とボタン以外は全て OFF にするのが良いと思います。デフォルトでは ON になっていますが、微妙に実行時間に負荷をかけていると思われます。 ここに掲載したサンプルは Panel の背景とかをデフォルト設定のまま使っているので、自分でカスタマイズして使ってください。 変更・再配布可・商用利用可。これ全体をアセットストアとかで有料販売するのだけはナシねぐらいの感じで使ってください。 最後に宣伝ですが、この記事が少しでも役に立ったという方は、人魚Daysアプリをダウンロードだけでもして頂けると励みになります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

reflection サンプル

static class を使う場合 var static_flg = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 得たメソッドの返り値が Taskか bool isAwaitable(MethodInfo m) { var rtype = m.ReturnType; var ch = typeof(Task).ToString(); if (rtype.ToString().IndexOf(ch) == -1) return false; return true; } using System; using System.Reflection; using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; public class X { public void hoge() { Console.WriteLine("X hoge"); } public void hogeArg(int i){ Console.WriteLine($"X hogeArg {i}"); } } public static class sX { public static void hoge() { Console.WriteLine("sX hoge"); } public static async Task hogeTask() { Console.WriteLine("sX hogeTask"); } public static async Task<bool> hogeTaskBool() { Console.WriteLine("sX hogeTaskBool"); return true; } public static async Task<string> hogeTaskDelay(int ms){ await Task.Delay(ms); var mes = $"xX hogeTaskDelay {ms}"; Console.WriteLine(mes); return mes; } } public static class Program { static async Task Main(string[] args) { /* using System.Reflection; using System.Threading.Tasks; */ //instance class var cls = new X(); var type = cls.GetType(); var fn = type.GetMethod("hoge"); if(fn==null) return; /*notfound method*/ fn.Invoke(cls, new object[] { }); var fn1 = type.GetMethod("hogeArg"); fn1.Invoke(cls, new object[] { 9999 }); //static class var static_flg = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type2 = typeof(sX);// var fn2 = type2.GetMethod("hoge", static_flg); fn2.Invoke(null, new object[] { }); //task check var fn3 = type2.GetMethod("hogeTask", static_flg); var fn4 = type2.GetMethod("hogeTaskBool", static_flg); Console.WriteLine(isAwaitable(fn3)); //true Console.WriteLine(isAwaitable(fn4)); //true Console.WriteLine("--------------"); Console.WriteLine(isAwaitable(fn)); //false Console.WriteLine(isAwaitable(fn2)); //false bool isAwaitable(MethodInfo m) { var rtype = m.ReturnType; var ch = typeof(Task).ToString(); if (rtype.ToString().IndexOf(ch) == -1) return false; return true; } //apply var call =typeof(sX).GetMethod("hogeTaskDelay",static_flg); if(isAwaitable(call)){ var ret = await (dynamic)call.Invoke(null,new object[]{ 5*1000 }); } else{ var ret = (dynamic)call.Invoke(null, new object[] { 5 * 1000 }); } } }//class Program
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# PDFドキュメントをOFDに変換

OFDファイルは、Cypresslogic Systems Inc.によって開発されたObjectView Form Definitionです。OFDは、一般的にObjectView Form Definitionファイルに関連付けられているファイル拡張子です。今日は、C#でFree.Spire.PDFを使ってPDFドキュメントをOFDに変換に変換する方法を紹介します。 下準備 1.E-iceblueの公式サイトからFree Spire.PDF無料版をダウンロードしてください。   2.Visual Studioを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire. PDF.dllを参照に追加してください。(Net 4.0を例としたら、デフォルトパスは“Bin→NET4.0→PDF.dll”というようです。) using Spire.Pdf; namespace PDFtoOFD { class Program { static void Main(string[] args) { PdfDocument pdf = new PdfDocument(); pdf.LoadFromFile("test.pdf"); pdf.SaveToFile("ToOFD.ofd", FileFormat.OFD); } } } 実行結果  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

StringExtension

ToValue<T> var x="100+100".ToValue<int>(-1);//200 ToMap var dic =new Dictionary<string,string>(){ $a...} var rep="$a".ToMap(dic); //ex)$a replace dic["$a"] using System; using System.Collections.Generic; using static System.Console; using System.Text.RegularExpressions; using System.Linq; class Program { static void Main(string[] args) { var dic =new Dictionary<string,string>(){ {"$a","100"}, {"$aa","200"}, {"$aaa","-300"}, }; var x="$a+1"; var a=x.ToMap(dic);//100+1 var b=a.ToValue<int>(-1);//101 var c="$a+1>100".ToMap(dic).ToValue<bool>(false);//true var d="360.1%90".ToValue<int>(-1);//0 var e="$a+$aa==300".ToMap(dic).ToValue<bool>(false);//true; var f="100/5>100/6".ToValue<bool>(false);//true; Console.WriteLine("Hello World!"); } } StringExtensions public static class CmdlineEx { static bool isMathable(this string me) { var rule = Regex.Escape("0123456789.+-/*%!<>="); var pattern = "^[" + rule + "]+$"; return Regex.IsMatch(me, pattern); } static bool isNumable(this string me) { var pattern = @"^[+\-]?[0-9]+\.[0-9]+$|^[+\-]?[0-9]+$"; return Regex.IsMatch(me, pattern); } static bool isCompareble(this string me) { var rule = Regex.Escape("!<>="); var pattern = "[" + rule + "]"; return Regex.IsMatch(me, pattern); } static bool ToCompare(this string code) { //a > b var map = new Dictionary<string, Func<decimal, decimal, bool>>(); map["=="] = (a, b) => a == b; map["!="] = (a, b) => a != b; map[">="] = (a, b) => a >= b; map["<="] = (a, b) => a <= b; map[">"] = (a, b) => a > b; map["<"] = (a, b) => a < b; bool f(string d) => Regex.IsMatch(code, Regex.Escape(d)); if (!map.Keys.Any(f)) return false; var ch = map.Keys.Where(f).First(); var ary = code.Split(ch, 2) .Select(d => d.Trim()) .Select(d => d.ToMath()) .ToArray() ; return map[ch](ary[0], ary[1]); } static decimal ToMath(this string code) { var map = new Dictionary<string, Func<decimal, decimal, decimal>>(); map["+"] = (a, b) => a + b; map["-"] = (a, b) => a - b; map["*"] = (a, b) => a * b; map["/"] = (a, b) => a / b; map["%"] = (a, b) => (int)a % (int)b; bool f(string d) => Regex.IsMatch(code, Regex.Escape(d)); if (!map.Keys.Any(f)) return f2(code); var ch = map.Keys.Where(f).First(); var ary = code.Split(ch, 2) .Select(d => d.Trim()) .Select(d => f2(d)) .ToArray() ; return map[ch](ary[0], ary[1]); // decimal f2(string s) { if (decimal.TryParse(s, out var x)) return x; else return s.GetHashCode(); } } public static T ToValue<T>(this string me, T falseValue) where T : IComparable { if (typeof(T) == typeof(string)) return (T)(object)me; // if (typeof(T) == typeof(bool)) { decimal vv; if (me.isCompareble()) return (T)(object)me.ToCompare(); else vv = me.ToValue<decimal>(-1); // var wk = (int)vv; if (wk == 1) return (T)(object)true; else if (wk == 0) return (T)(object)false; return falseValue; } /// decimal v;//数値は一度decimalへ if (me.isMathable()) { v = me.ToMath(); } else if (!decimal.TryParse(me, out v)) return falseValue; if (typeof(T) == typeof(decimal)) return (T)(object)v; if (typeof(T) == typeof(double)) return (T)(object)(double)v; if (typeof(T) == typeof(float)) return (T)(object)(float)v; if (typeof(T) == typeof(int)) return (T)(object)(int)v; if (typeof(T) == typeof(bool)) { var wk = (int)v; if (wk == 1) return (T)(object)true; else if (wk == 0) return (T)(object)false; return falseValue; } return falseValue; } public static string ToMap(this string me,Dictionary<string,string> dic,char ch='$') { ///辞書を使って値を代入する。シンボルは$ if (!Regex.IsMatch(me, Regex.Escape("" + ch))) return me; var keys = dic.Keys .Where(d => d.IndexOf(ch) != -1) .OrderByDescending(d => d.Length) ; foreach (var k in keys) me = me.Replace(k, dic[k]); return me; } ///配列は必ず空白文字で初期化されている。 public static List<string> ToArgs(this string me, int pnum, char sep = ' ') { var ret = Enumerable.Repeat("", pnum).ToList(); var ary = me.Split(sep, pnum); for (var i = 0; i < ary.Length; i++) ret[i] = ary[i]; return ret; } public static string ToLF(this string code) { return Regex.Replace(code,"\r\n|\r|\n","\n"); } } 逆ポーランドは無し。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む