- 投稿日:2020-02-21T21:25:27+09:00
『Unity C# 個人用メモ』 アイテムの生成一括と一括削除
public class Seisei : MonoBehaviour { //生成したいオブジェクトを宣言 [SerializeField] GameObject obj = default; void Update() { //一括生成 if (Input.GetMouseButtonDown(0)) { //x座標用 for (int xi = 0; xi < 5; xi++) { //y座標用 for (int zi = 0; zi < 3; zi++) { //生成(対象,座標,角度) Instantiate(obj, new Vector3(xi, 1f, zi), Quaternion.identity); } } }//一括削除 if (Input.GetMouseButtonDown(1)) { //あらかじめオブジェクトにタグをつけておいて、そのタグのついたオブジェクトをまとめて配列にぶち込む GameObject[] objs = GameObject.FindGameObjectsWithTag("obj"); //配列onjsにぶち込んだものをを一纏めにする foreach(GameObject clone in objs) { Destroy(clone); } } }}
- 投稿日:2020-02-21T21:25:27+09:00
『Unity C# 個人用メモ』 アイテムの一括生成と一括削除
public class Seisei : MonoBehaviour { //生成したいオブジェクトを宣言 [SerializeField] GameObject obj = default; void Update() { //一括生成 if (Input.GetMouseButtonDown(0)) { //x座標用 for (int xi = 0; xi < 5; xi++) { //y座標用 for (int zi = 0; zi < 3; zi++) { //生成(対象,座標,角度) Instantiate(obj, new Vector3(xi, 1f, zi), Quaternion.identity); } } }//一括削除 if (Input.GetMouseButtonDown(1)) { //あらかじめオブジェクトにタグをつけておいて、そのタグのついたオブジェクトをまとめて配列にぶち込む GameObject[] objs = GameObject.FindGameObjectsWithTag("obj"); //配列onjsにぶち込んだものをを一纏めにする foreach(GameObject clone in objs) { Destroy(clone); } } }}
- 投稿日:2020-02-21T20:11:57+09:00
#OpenCV Sharpでメモリリークが起きる
本内容を利用した場合の一切の責任を私は負いません。
Matをusingしてるのに起きた。
(下記の公式サンプルでusingしてるためアンマネージ。
https://github.com/shimat/opencvsharp_samples/
)
検索したら下記が見つかって、自分はMat取得ではなくBitmap取得(Mat.ToBitmapメソッド)だから該当しないと思ったけど、Disposeしたら防止できた。
https://blog.mohyo.net/2015/03/1313/
てことで、Matから取得したアンマネージは全てDisposeした方がよさそう。
- 投稿日:2020-02-21T20:08:45+09:00
今更ながらWPFに置き換えてみる(1)
この前新しいノートPC買った。
レノボのX1。すこぶる快適なんですが、以前作ったツールアプリの表示が汚い。解像度の問題で仕方ないのはわかっているんですが何とかしたいと考えてWPFで作り直すことにします。
どうせ作り直すので、VBからC#に置き換えもやってみようかと。
↑超ボケボケ。ひどい。
機能は自分ツールなんであまりなく
・常駐型アプリ
・NotifyIconの動的生成(数種類)
・時報表示
くらい。いまさらWPFってのもあれですが自分用の備忘録として進めていきます。
- 投稿日:2020-02-21T19:59:08+09:00
#OpenCV SharpのVideoCapture.IsOpenedメソッドがtrueにならない
本内容を利用した場合の一切の責任を私は負いません。
コンストラクタで動画ファイルを指定した場合。
Readメソッドで取得したMatも使用できない。
動画ファイルのファイル名が原因ぽい。
「?」が入っていると例外は発生しないが事象が起こる。
Unicodeのせい???と検索したら、既に下記で問題視されてるように見える。
https://github.com/shimat/opencvsharp/issues/342
で、更に追うと、下記から元のOpenCVの問題っぽく見え、チケットがクローズしてないのでまだ修正されてないのかも。
https://github.com/opencv/opencv/pull/13368
とりあえず、ファイル名を変えれば回避できる。
- 投稿日:2020-02-21T19:33:47+09:00
『Unity C# 初心者メモ』オブジェクトをランダムな座標へ一定時間ごとに移動させる
自分用メモ
わざと区切ってるけど全部1枚の流れ必要になる素材を作る
public class RandomIdou : MonoBehaviour { //座標を再計算しても良いかの判定 private bool bl = true; //移動先の座標 private Vector3 pos; //x座標代入用 private float x; //z座標代入用 private float z; //移動する速度 private float speed = 3f; //移動範囲計算用 private int i = 5;初動用の座標を作る
void Start() { //Randomな値を代入する x = Random.Range(-i, i); z = Random.Range(-i, i); //↑で出た値を座標に代入する pos = new Vector3(x, transform.position.y, z); }座標の移動と再計算
void Update() { //移動するときの速度用 float step = speed * Time.deltaTime; //座標をpos座標へstepの速度で移動させる transform.position = Vector3.MoveTowards(transform.position, pos, step); //座標の再計算を行ってよく、座標が目的地に着いた時 if (bl == true && transform.position == pos) { //2秒後再計算を行う Invoke("Idou", 2f); //毎フレーム計算しない様に判定を変える bl = false; } }再計算用のメソッド
void Idou() { //移動するときの値への減少率を計算 float xp = 1f - System.Math.Abs(transform.position.x) / 5f; float zp = 1f - System.Math.Abs(transform.position.z) / 5f; //x座標が中心より大きい時(中央より右側へ行ったとき if (transform.position.x > 0) { //右側へ移動する範囲にのみ減少率を掛けRandomな値を計算する x = Random.Range(-i, i * xp); } //x座標が中心より小さい時(中央より左側へ行ったとき else { //左側へ移動する範囲にのみ減少率を掛けRandomな値を計算する x = Random.Range(-i * xp, i); } //y座標ver(以下略 if (transform.position.z > 0) { z = Random.Range(-i, i * zp); } else { z = Random.Range(-i * zp, i); } //目的地座標posに計算結果の値を代入する pos = new Vector3(x, transform.position.y, z); //再計算をしてもよい判定を付ける bl = true; }
- 投稿日:2020-02-21T17:32:43+09:00
『Unity C# 個人用メモ』 WASDや矢印キーでオブジェクトの位置を動かす
自分用メモであり同じような初心者の方へ向けた自分なりの解説
名称がちゃんとあっているのかどうかは正直わかりませnオブジェクトの位置を動かす場合
位置を一瞬で移動させる
object の 座標 は 座標宣言 x y z transform.position = new Vector3( 3f, 0, 2f);とすればオブジェクトの位置が
x座標が3f
,y座標は0
,x座標が2f
となる少しずつ移動させる
transform.position = new Vector3(transform.position.x, transform.position.y, transform.position.z+0.2f);
void Update
内にこのように書くと少しずつ奥に進むようになる
呼ばれる度にオブジェクトをz軸
方向へ0.2f
を足すという意味WASDや矢印キーを入力をしたときに移動させる
適当に作ったゲームオブジェクトに
Rigidbody
コンポーネントを追加してから
以下の様にスクリプトを書くpublic class NewBehaviourScript : MonoBehaviour { //Rigidbody型のrbという変数を作る private Rigidbody rb; //float型のpowerという変数を作り、3fを代入する private float power = 3f; private void Start() { //リジットボディを取得しrbに代入する rb = GetComponent<Rigidbody>(); } void Update() { //キー入力による値を代入(解説は後で float x = Input.GetAxisRaw("Horizontal"); float z = Input.GetAxisRaw("Vertical"); //↑で代入された値をVector3型のIdouHoukouという変数に代入する Vector3 IdouHoukou = new Vector3(x, 0, z); //rbに力を加える //velocityは質量などの物理演算を無視するときに使う rb.velocity = IdouHoukou * power; //rbの回転をさせない様にする rb.constraints = RigidbodyConstraints.FreezeRotation; //移動範囲の制限 transform.position = new Vector3( Mathf.Clamp(transform.position.x, -5f, 5f), Mathf.Clamp(transform.position.y,1f,1f), Mathf.Clamp(transform.position.z, 5f, 5f)); } }これでWASDや矢印キーを入力したときに移動が出来るようになります
Input.GetAxisRaw("Horizontal"); Input.GetAxisRaw("Vertical");
Input.GetAxisRaw
とは入力された物に対してint型(整数)で-1~1を返す
Horizontal
はA
,D
と←
,→
がUnityに初期設定として登録されており、
A
や←
が入力されている時は-1
、
何も入力されていない時は0
、
D
や→
が入力されている時は1
を返す同じように
Vertical
は、
s
と↓
が入力されている時は-1
、
何も入力されていない時は0
、
w
と↑
が入力されている時は1
を返すつまり先ほど書いた以下の
Vector3 idou = new Vector3(x, 0, z);
new Vector3(x, 0, z)
このx
部分とz
部分に-1
,0
,1
が代入されるその後
rb.velocity = idou * speed;とあるので
x
の値が-1
ならx(-1)*speed(3f)
となりx軸
に-3f
の力を加える
x
の値が0
ならx(0)*speed(3f)
となりx軸
に0
の力を加える
x
の値が1
ならx(1)*speed(3f)
となりx軸
に3f
の力を加える
ということになる
y軸
も同じ考えなので割愛rb.constraints = RigidbodyConstraints.FreezeRotation;こちらはゲームオブジェクトのインスペクタ内の
Rigidbody
コンポーネントの下部にある
constraints
という項目の2段目にある
回転するかどうかのチェックマークをスクリプト上でつけているだけなので
チェックマークを付けた場合は記入しなくても問題はありません。(てかチェック付けた方が楽)このままだと入力がある限り際限なく移動し続けるので制限をつけます
transform.position = new Vector3( Mathf.Clamp(transform.position.x, -5f, 5f), Mathf.Clamp(transform.position.y,1f,1f), Mathf.Clamp(transform.position.z, -5f, 5f));
Mathf.Clamp(対象,最小値,最大値)
を使用することで
簡単にtransform.position
がMathf.Clamp()
内の範囲以上には移動できなくなるという処理が作れます
使わない場合if (transform.position.x >= -5f) { transform.position = new Vector3(-5f, transform.position.y, transform.position.z); }こんな感じの物を
x
,y
,z
それぞれ2パターンで合計6回も書くことになるのでMathf.Clamp
は偉大です以上
- 投稿日:2020-02-21T15:27:35+09:00
DataGridのSelectedItemsがbind出来ない!!
0. はじめに
Freeradicalの中の人、yamarahです。
普段は、Autodesk InventorのAddIn作成に関する記事を書いています。
今回は、WPFのDataGrid
において、複数選択を許可した場合に、選択状態をどのようにViewModelにbindするかという記事です。
WPF自体は詳しくないので、おかしな点があればご指摘歓迎です。20.02.21 17:55 JST 追記
やっぱり仮想化をオフしないと、連動しませんでした。
具体的には、視界外のIsSelected
をtrue
にしても、無視されるようです。
解決策が見つかれば、記事を更新します。work aroundがあれば、よろおねです。1. 方針
まず前提として、
DataGrid.SelectedItems
はbindできません。単選択なら問題になりませんが、複数選択の状態を知るには少し手間が必要です。
では、方針ですが、概ね次の記事に従います。リンク : ListViewの選択項目を取得/設定する
つまりは、
ListViewItem.IsSelected に対するバインディングは OneWay (VM -> Vのみ)にする
ListView.SelectedItems の内容は一切信用しない
VからVMへの反映は、SelectionChanged イベントで自力でやるということです。
SelectedItems
のようなCollectionを用意するのではなく、各Item内のIsSelected
を選択状態と同期するようになります。
ただし、折角だからコードビハインドは嫌だよね、ってことで、Behaviorを使って実装します。2. Item側の準備
Behaviorに汎用性を持たせたいので、
IsChecked
はData型に直接書くのではなく、基底classに書いてそれを継承するようにします。CollectionItemWithIsSelectedProperty.csusing System.ComponentModel; namespace TestApp { public class CollectionItemWithIsSelectedProperty : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged = null; private bool _IsSelected; public bool IsSelected { get => _IsSelected; set { if (_IsSelected != value) { _IsSelected = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected))); } } } } }では、これを継承したテスト用のclassを作ります。
PathInfo.csusing System.IO; namespace TestApp { class PathInfo : CollectionItemWithIsSelectedProperty { public string Directory { get; private set; } public string FileName { get; private set; } public PathInfo(string fullFileName) { Directory = Path.GetDirectoryName(fullFileName); FileName = Path.GetFileName(fullFileName); } } }3 View → ViewModelのBehavior
SelectionChanged
をhookして、選択状態の変化を各Itemに設定します。NotifyIsSelectedToSouceBehavior.csusing Microsoft.Xaml.Behaviors; using System.Windows.Controls; namespace TestApp { /// <summary> /// 選択状態をItem.IsSelectedに反映するBehavior /// </summary> class NotifyIsSelectedToSouceBehavior : Behavior<DataGrid> { protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.SelectionChanged += DataGrid_SelectionChanged; } protected override void OnDetaching() { base.OnDetaching(); this.AssociatedObject.SelectionChanged -= DataGrid_SelectionChanged; } private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (CollectionItemWithIsSelectedProperty addedItem in e.AddedItems) { addedItem.IsSelected = true; } foreach (CollectionItemWithIsSelectedProperty removedItem in e.RemovedItems) { removedItem.IsSelected = false; } } } }4. SelectedItemsCountのBehavior
やっぱり、選択数は欲しいですよね。ItemsSourceをなめて
IsSelected
を数えるのは非効率なので、これもBehaviorを作ります。BindSelectedItemsCountBehavior.csusing Microsoft.Xaml.Behaviors; using System.Windows; using System.Windows.Controls; namespace TestApp { /// <summary> /// DataGrid内のSelectedItems.Countに相当する値を返すBehavior /// </summary> public class BindSelectedItemsCountBehavior : Behavior<DataGrid> { protected override void OnAttached() { base.OnAttached(); AssociatedObject.SelectionChanged += DataGrid_SelectionChanged; } protected override void OnDetaching() { AssociatedObject.SelectionChanged -= DataGrid_SelectionChanged; base.OnDetaching(); } public static DependencyProperty SelectedItemsCountProperty = DependencyProperty.Register("SelectedItemsCount", typeof(int), typeof(BindSelectedItemsCountBehavior), new PropertyMetadata(null)); public int SelectedItemsCount { get { return (int)GetValue(SelectedItemsCountProperty); } set { SetValue(SelectedItemsCountProperty, value); } } void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { SelectedItemsCount += e.AddedItems.Count; SelectedItemsCount -= e.RemovedItems.Count; } } }5. Interaction.Behaviorsを使えるようにする
さて、いよいよxamlに記載・・・の前に、xaml内にBehaviorを記述するのに準備が必要です。
ググると、BlendのSDKを・・・という記事がヒットしますが、VS2019では勝手が違うので注意。
リンク : 新しい Behavior ライブラリへの更新 #27
xamlの名前空間指定は、次のようになります。<Window ・・・続く xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors; assembly=Microsoft.Xaml.Behaviors"6. サンプルコード
まずは、Viewから。
TestView.xml<Window x:Class="TestApp.TestView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors" xmlns:local="clr-namespace:TestApp" mc:Ignorable="d" Title="TestView" Height="300" Width="300"> <DockPanel> <TextBlock DockPanel.Dock="Top" Text="{Binding SelectedItemsCountReport}"/> <DataGrid ItemsSource="{Binding PathInfoList, Mode=OneWay}" SelectionMode="Extended" IsReadOnly="True" GridLinesVisibility="None" HeadersVisibility="Column" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Width="SizeToHeader" Header="IsSelected" Binding="{Binding IsSelected}"/> <DataGridTextColumn Width="*" Header="パス" Binding="{Binding Directory}"/> <DataGridTextColumn Width="SizeToCells" MinWidth="70" Header="ファイル名" Binding="{Binding FileName}"/> </DataGrid.Columns> <DataGrid.RowStyle> <Style TargetType="{x:Type DataGridRow}"> <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWay}"/> </Style> </DataGrid.RowStyle> <i:Interaction.Behaviors> <local:NotifyIsSelectedToSouceBehavior/> <local:BindSelectedItemsCountBehavior SelectedItemsCount="{Binding SelectedItemsCount, Mode=OneWayToSource}"/> </i:Interaction.Behaviors> </DataGrid> </DockPanel> </Window>
- ViewModel → Viewの
IsSelected
のbindは、<DataGrid.RowStyle> <Style TargetType="{x:Type DataGridRow}"> <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWay}"/> </Style> </DataGrid.RowStyle>
- View → ViewModelの
IsSelected
とSelectedItemsCount
のbindは、<i:Interaction.Behaviors> <local:NotifyIsSelectedToSouceBehavior/> <local:BindSelectedItemsCountBehavior SelectedItemsCount="{Binding SelectedItemsCount, Mode=OneWayToSource}"/> </i:Interaction.Behaviors>です。bind方向の指定は、上記の通りに忘れず設定してください。せっかくコードを書いたんだから、
SelectedItemsCount
のModeのDefault値をOneWayToSource
にしたかったのですが、簡単には出来ないようなので諦めました。次に、ViewModelです。
TestViewModel.csusing System.Collections.ObjectModel; using System.ComponentModel; namespace TestApp { class TestViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; public ObservableCollection<PathInfo> PathInfoList { get; private set; } private int _SelectedItemsCount; public int SelectedItemsCount { get => _SelectedItemsCount; set { if (_SelectedItemsCount != value) { _SelectedItemsCount = value; SelectedItemsCountReport = $"SelectedItemsCount : {_SelectedItemsCount}"; } } } private string _SelectedItemsCountReport = string.Empty; public string SelectedItemsCountReport { get => _SelectedItemsCountReport; set { if (_SelectedItemsCountReport != value) { _SelectedItemsCountReport = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedItemsCountReport))); } } } public TestViewModel() { PathInfoList = new ObservableCollection<PathInfo> { new PathInfo(@"C:\temp\file0001.txt") { IsSelected = true }, new PathInfo(@"C:\temp\file0002.txt") { IsSelected = true }, new PathInfo(@"C:\temp\file0003.txt") { IsSelected = false }, new PathInfo(@"C:\temp\file0004.txt") { IsSelected = true }, new PathInfo(@"C:\temp\file0005.txt") { IsSelected = false } }; } } }実際のアプリケーションでは、SelectedItemsCountにReactivePropertyなどを使うことになるでしょう。
7. 動作結果
では、これらのコードでWindowを表示してみましょう。(スタートアップのコードは、各自でどうぞ)
選択状態を変化させると、上端の選択数と、左端桁のTrue
/False
が変化するのが見て取れます。8. とはいえ、
SelectedItems
が欲しいよねという方は、次の記事を参考にどうぞ。
リンク : WPFのDataGridで選択された複数のアイテムをバインドするためのビヘイビア
- 投稿日:2020-02-21T14:49:57+09:00
『Unity C#』ガチ初心者の自分用メモ 型とか演算子
よく使う型
int ・・・整数 /// -1,0,1flot・・・小数点以下を含む /// fが必須 -1.5f,1.5fstring・・・文字列 /// ""が必須 "こんにちは"bool()・・・真偽判定 /// true(真) or false(偽)Vector3(2)・・・座標とかベクトル /// VectorのVは大文字なのを忘れないで!! /// 使う時は Vector3 zahyou = new Vector3(〇,〇,〇)の様に宣言する /// Vector2の場合なら new Vector2(〇,〇)の様な感じGameObject・・・ゲームオブジェクト /// 用途によってGameObjectとgameObjectの二つ使い分けるので気を付ける /// 宣言するときは```private GameObject ○○ ```など /// 使用するときは```gameObject.GetComponent<〇〇>();```などTransform・・・トランスフォーム。オブジェクトのインスペクタ(Unity画面の右側)の上の方にある座標とか回転入力するときに使うやつ /// 宣言するときは```private Transform ○○;```など ///使用するときは```transform.position;```など演算子
計算で使うやつ
四則演算省略
+=
追加(=
が後ろ)
-=
差引(=
が後ろ)
++
1増やす
--
1減らす
=
代入if分で使うやつ
==
同じであるとき
!=
同じではない時
&&
どちら[も]
||
どちら[か]
>
大なり
>=
大なりイコール(=
が後ろ)
<
小なり
>=
小なりイコール(=
が後ろ)
- 投稿日:2020-02-21T13:59:26+09:00
『Unity C# 個人用メモ』 ガチ初心者の自分用の用語メモ
初心者の自分用のメモ
大体こんな感じだよって思ってればいいやつMonoBehaviour(モノビヘイビア)
全てのスクリプトから派生するベースクラス
ヒエラルキービュー
画面左。シーンビューに配置したオブジェクトの一覧、階層構造。
プロジェクトビュー
画面下。ゲームで使う素材を管理。
インスペクタ
画面右。選択しているオブジェクトの詳しい情報がわかる。 座標・オブジェクトの大きさ・配置など。
メソッド
void Start() { }メソッドとはこのvoid 〇〇のこと。上の物であればStart()がメソッドになる
アクセス修飾子
public int = 1;
private int = 1;
アクセス修飾子とはこのpublicやprivateのこと変数・型
int a ;int ← 型
a ← 変数
intという型のaという変数を作るという意味になる引数(ひきすう)
Vector3 zahyou = new Vector3(〇,〇,〇);new Vector3(〇,〇,〇);〇のことなど
- 投稿日:2020-02-21T00:20:34+09:00
非同期ストリーム IAsyncEnumerable<T> から一定個数ずつ列挙する
このドキュメントの内容
C# 8.0 で追加された非同期ストリーム(IAsyncEnumerable<T>)から一定個数ずつオブジェクトを列挙する方法を紹介します。一定個数ずつバッファリングしながら処理を行いたい、バッファリングの手段はそれぞれの処理の実装に委ねたいというような場面で使うことを想定しています。
IAsyncEnumerable<T> インターフェースに対する拡張メソッドとして実装しました。
Chunkメソッド/// <summary> /// 指定された非同期ストリームから一定個数ずつオブジェクトを列挙します。 /// </summary> /// <param name="enumerable">列挙対象の非同期ストリーム</param> /// <param name="chunkSize">一度に取得する個数</param> /// <param name="cancellationToken">キャンセルトークン</param> /// <returns>一定個数ずつオブジェクトを列挙する非同期ストリーム</returns> public static IAsyncEnumerable<IAsyncEnumerable<T>> Chunk<T>( this IAsyncEnumerable<T> enumerable , int chunkSize , CancellationToken cancellationToken = default )サンプルコード
あまり現実的な内容ではありませんが、ArrayPool<T> と Span<T> を使って一定個数ずつバッファリングする例です。
private static async Task ChunkEnumerateSample() { SampleData[] buffer = ArrayPool<SampleData>.Shared.Rent(3); try { // 3つずつ列挙する await foreach (var chunk in GetSampleData().Chunk(3)) { Console.WriteLine("----- start chunk -----"); await DoSomethingAsync(chunk, buffer); Console.WriteLine("----- end chunk -----"); } } finally { ArrayPool<SampleData>.Shared.Return(buffer); } } private static async Task DoSomethingAsync(IAsyncEnumerable<SampleData> enumerable, SampleData[] buffer) { int count = 0; await foreach (var obj in enumerable) { buffer[count++] = obj; } DoSomething(buffer, count); } private static void DoSomething(SampleData[] buffer, int length) { var span = new Span<SampleData>(buffer, 0, length); for (int i = 0; i < span.Length; ++i) { Console.WriteLine($"{span[i].Value}"); } } // 10個のオブジェクトを返す private static async IAsyncEnumerable<SampleData> GetSampleData() { await Task.Yield(); for (int i = 0; i < 10; ++i) { yield return new SampleData(i); } } public class SampleData { public SampleData(int value) { Value = value; } public int Value { get; } }拡張メソッド Chunk の実装内容
public static class AsyncEnumerableExtensions { /// <summary> /// 指定された非同期ストリームから一定個数ずつオブジェクトを列挙します。 /// </summary> /// <param name="enumerable">列挙対象の非同期ストリーム</param> /// <param name="chunkSize">一度に取得する個数</param> /// <param name="cancellationToken">キャンセルトークン</param> /// <returns>一定個数ずつオブジェクトを列挙する非同期ストリーム</returns> public static IAsyncEnumerable<IAsyncEnumerable<T>> Chunk<T>( this IAsyncEnumerable<T> enumerable , int chunkSize , CancellationToken cancellationToken = default ) { return Chunk(enumerable, chunkSize, new NullState(), cancellationToken); } /// <summary> /// 指定された非同期ストリームから一定個数ずつオブジェクトを列挙します。 /// </summary> /// <param name="enumerable">列挙対象の非同期ストリーム</param> /// <param name="chunkSize">一度に取得する個数</param> /// <param name="state">列挙状態を管理するオブジェクト</param> /// <param name="cancellationToken">キャンセルトークン</param> /// <returns>一定個数ずつオブジェクトを列挙する非同期ストリーム</returns> public static async IAsyncEnumerable<IAsyncEnumerable<T>> Chunk<T>( this IAsyncEnumerable<T> enumerable , int chunkSize , IAsyncEnumerablorState state , [EnumeratorCancellation]CancellationToken cancellationToken = default ) { await using (IAsyncEnumerator<T> enumerator = enumerable.GetAsyncEnumerator(cancellationToken)); while (!state.IsEof) { yield return new ChunkAsyncEnumerable<T>(enumerator, chunkSize, state); } } private class NullState : IAsyncEnumerablorState { internal bool IsEof { get; set; } internal void OnMoveNext() {} } private readonly struct ChunkAsyncEnumerable<T> : IAsyncEnumerable<T> { internal ChunkAsyncEnumerable( IAsyncEnumerator<T> enumerator , int chunkSize , IAsyncEnumerablorState state ) { m_Enumerator = enumerator; m_ChunkSize = chunkSize; m_State = state; } private readonly IAsyncEnumerator<T> m_Enumerator; private readonly int m_ChunkSize; private readonly IAsyncEnumerablorState m_State; private async IAsyncEnumerable<T> Enumerate() { int count = 0; while (await m_Enumerator.MoveNextAsync().ConfigureAwait(false)) { yield return m_Enumerator.Current; ++count; m_State.OnMoveNext(); if (count >= m_ChunkSize) { yield break; } } m_State.IsEof = true; } public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) { return Enumerate().GetAsyncEnumerator(cancellationToken); } } } public interface IAsyncEnumerablorState { bool IsEof { get; set; } void OnMoveNext(); }サンプルコードの実行結果
3個ずつ列挙され、最後の端数も正しく列挙されています。
----- start chunk ----- 0 1 2 ----- end chunk ----- ----- start chunk ----- 3 4 5 ----- end chunk ----- ----- start chunk ----- 6 7 8 ----- end chunk ----- ----- start chunk ----- 9 ----- end chunk -----
- 投稿日:2020-02-21T00:10:42+09:00
Rx.NETでWindows Formを操作するメモ
ポーリング処理のサンプル
System.Reactive
をNUGETから入れるthis.ticker= Observable.Interval(new TimeSpan(0, 0, 15));
でObserverを作るthis.ticker.Subscribe( (item) => { // 任意のコントロールを操作する例 // Control.Invokeでコントロールを操作するメソッドを呼び出すと実現できる this.AnyControl.Invoke(new UseControlDelegate(this.UseControlMethod)); } );どうでもいいけどRx.NETってちゃんとしたリファレンスなくね?