class Data
{
publicvoid Run();
}
class Bug
{
privatereadonlyobject _Locker = new ();
private Data _Data;
publicvoid Test1()
{
lock (_Locker)
{
_Data = new ();
}
}
publicvoid Test2()
{
var data = _Data;
data.Run();
}
}
ロックしてから処理しないとダメ。
publicvoid Test2()
{
Data data;
lock (_Locker)
{
data = _Data;
}
data.Run();
}
var sample = new Sample();
Task.Run(async () =>
{
await Task.Deley(TimeSpan.FromSeconds(60)) // heavy work
sample.IsFinished = true;
})
while (!sample.IsFinished)
{
// do something
}
class Sample
{
publicbool IsFinished; // volatile
}
古式ゆかしい if 文と、パターンマッチングを利用した if 文です。二つの式は同じうごきをしますが、デコンパイルした C# のコードに違いはあるのかチェックしてみる。(クラスとメソッドはなくてもいいのですが、デコンパイルコードと比較しやすいように掲載)
using System;
publicclass Test
{
publicstaticvoid Main()
{
var a = (x:1, y:2);
if (a.x == 1 && a.y == 2)
{
Console.WriteLine("A");
}
if (a is { x: 1, y: 2 })
{
Console.WriteLine("B");
}
}
}
publicclass Test
{
publicstaticvoid Main()
{
ValueTuple<int, int> valueTuple = new ValueTuple<int, int>(1, 2);
if (valueTuple.Item1 == 1 && valueTuple.Item2 == 2)
{
Console.WriteLine("A");
}
if (valueTuple.Item1 == 1 && valueTuple.Item2 == 2)
{
Console.WriteLine("B");
}
}
}
パターンマッチングのなかで _ をつかって、なんでもいい値を表現することがあると思います。
using System;
publicclass Test
{
publicstaticvoid Main()
{
var p = (x: 10, y: 20);
if (p.Item1 == 10) Console.WriteLine("A");
if (p is {x: 10, y: _}) Console.WriteLine("B");
if (p is {x: 10 }) Console.WriteLine("C");
}
}
B と C を出力する式は、同じ意味だとなんとなくわかると思います。下のように生成コードも同じです。(逆にこの場合は書いていても人の読みやすさだけに効果があり、実行時の処理コストは無い)
publicclass Test
{
publicstaticvoid Main()
{
ValueTuple<int, int> valueTuple = new ValueTuple<int, int>(10, 20);
if (valueTuple.Item1 == 10)
{
Console.WriteLine("A");
}
if (valueTuple.Item1 == 10)
{
Console.WriteLine("B");
}
if (valueTuple.Item1 == 10)
{
Console.WriteLine("C");
}
}
}
null チェックの比較
知らないと絶対意味がわからないパターンマッチングの null チェック。
using System;
publicclass Test
{
publicstaticvoid Main()
{
int? p = null;
if (p != null) Console.WriteLine("A");
if (p is not null) Console.WriteLine("B");
if (p is {}) Console.WriteLine("C");
}
}
完全に同じコードになります。安心した。わけのわからない追加コードはありません。
publicclass Test
{
publicstaticvoid Main()
{
Nullable<int> num = null;
if (num.HasValue)
{
Console.WriteLine("A");
}
if (num.HasValue)
{
Console.WriteLine("B");
}
if (num.HasValue)
{
Console.WriteLine("C");
}
}
}
using System;
publicclass Test
{
publicstaticvoid Main()
{
object i = 1;
if (i isint)
{
int i2 = (int)i;
Console.WriteLine(i2);
}
if (i isint i3)
{
Console.WriteLine(i3);
}
}
}
publicclass Test
{
publicstaticvoid Main()
{
object obj = 1;
// i2 のテストコードif (obj isint)
{
intvalue = (int)obj;
Console.WriteLine(value);
}
// i3 のテストコードint value2 = default(int);
int num;
if (obj isint)
{
value2 = (int)obj;
num = 1;
}
else
{
num = 0;
}
if (num != 0)
{
Console.WriteLine(value2);
}
}
}
using System;
publicclass Test
{
publicstaticvoid Main()
{
var p = (x: 10, y: 20);
var p1 = p switch
{
{ x: 10 } => "A",
{ y: >= 20 } => "B",
_ => "X"
};
Console.WriteLine(p1);
}
}
publicclass Test
{
publicstaticvoid Main()
{
ValueTuple<int, int> valueTuple = new ValueTuple<int, int>(10, 20);
int item = valueTuple.Item1;
string text;
if (item != 10)
{
int item2 = valueTuple.Item2;
text = ((item2 < 20) ? "X" : "B");
}
else
{
text = "A";
}
stringvalue = text;
Console.WriteLine(value);
}
}
もうひとつ似たようなパターンを見ておきます。ほとんど同じコードが生成されています。
using System;
publicclass Test
{
publicstaticvoid Main()
{
var p = (x: 10, y: 20);
string p2 = "";
switch (p)
{
case var (x, _) when x == 10:
p2 = "A";
break;
case var (_, y) when y >= 20:
p2 = "B";
break;
default:
p2 = "X";
break;
}
Console.WriteLine(p2);
}
}
publicclass Test
{
publicstaticvoid Main()
{
ValueTuple<int, int> valueTuple = new ValueTuple<int, int>(10, 20);
string text = "";
ValueTuple<int, int> valueTuple2 = valueTuple;
ValueTuple<int, int> valueTuple3 = valueTuple2;
int item = valueTuple3.Item1;
if (item != 10)
{
int item2 = valueTuple3.Item2;
text = ((item2 < 20) ? "X" : "B");
}
else
{
text = "A";
}
Console.WriteLine(text);
}
}
switch 文のパターンマッチング2
型をチェックするパターンマッチングの例です。先の例と変わらないかも。
publicclass Test
{
publicstaticvoid Main()
{
int a = 1;
Method(a);
}
publicstaticstring Method(object o)
{
string result = "";
switch (o)
{
caseint i when i > 0:
result = "A";
break;
casedouble d when d > 10:
result = "B";
break;
default:
result = "X";
break;
}
return result;
}
}
publicclass Test
{
publicstaticvoid Main()
{
int num = 1;
Method(num);
}
publicstaticstring Method(object o)
{
string text = "";
if (o isint)
{
int num = (int)o;
if (num > 0)
{
return"A";
}
}
elseif (o isdouble)
{
double num2 = (double)o;
if (num2 > 10.0)
{
return"B";
}
}
return"X";
}
}
ちなみに、when を and に変えたコード (C# 9.0) でも、生成コードは変わらなかったです。
using System;
publicclass Test
{
publicstaticvoid Main()
{
int a = 1;
Method(a);
}
publicstaticstring Method(object o)
{
string result = "";
switch (o)
{
caseint i and > 0:
result = "A";
break;
casedouble d and > 10:
result = "B";
break;
default:
result = "X";
break;
}
return result;
}
}
publicclass Test
{
publicstaticvoid Main()
{
int num = 1;
Method(num);
}
publicstaticstring Method(object o)
{
string text = "";
if (o isint)
{
int num = (int)o;
if (num > 0)
{
return"A";
}
}
elseif (o isdouble)
{
double num2 = (double)o;
if (num2 > 10.0)
{
return"B";
}
}
return"X";
}
}
ここでは、「Randam Number Generator」を作る方法について無料のガイドを見ることができます。すばらしい、5分もかからずプログラムを作れました。無料のオンラインリソースの数と Python の使いやすさによってインターネットと学習する意欲さえあれば、だれでもプログラミングできるようになりました。
なんでソフトウェアエンジニアリングが難しいか? (Why is Software Engineering Hard?)
ローカルのサンプルプログラムでも、GitHub にコミットするときなんかに API キーを使用していると困ることがあります。GitHub にサンプルコードをあげるときは、当然 API キーを隠します。で、API を使用する(実際に動作する)実行コードに書き換えるたびに Git の変更要素としてコミットのリストに挙げられてしまうことになります。あまり好ましい状態ではないですね。
API キーをコードに直接埋め込まないでください。コードに埋め込まれた API キーは、誤って公開されてしまう可能性があります。たとえば、共有するコードからキーを削除し忘れた場合などです。API キーはアプリケーションに埋め込む代わりに、アプリケーションのソースツリー外部にある環境変数やファイル内に保存します。
アプリケーションのソースツリー内のファイルに API キーを保存しないでください。API キーをファイルに保存する場合は、キーがソースコード制御システム内に保存されないよう、ファイルをアプリケーションのソースツリー外部に保持するようにします。これは特に、GitHub のような公共のソースコード管理システムを使用する場合に重要です。