この時変数 s に設定されている Sample のメンバーを別々にすべて取り出す実装例は以下の通りです。
publicstaticclass EnumExtension
{
publicstatic IEnumerable<T> GetFlagMembers<T>(this T self) where T : struct, Enum, IConvertible
{
var att = typeof(T).GetCustomAttributes<FlagsAttribute>();
if (att isnull)
{
thrownew NotSupportedException("This type is 'FlagsAttribute' not specified.");
}
ulong a = self.ToUInt64(System.Globalization.CultureInfo.InvariantCulture);
foreach (T m in Enum.GetValues<T>())
{
ulong b = m.ToUInt64(System.Globalization.CultureInfo.InvariantCulture);
if ((b & a) == b)
{
yieldreturn m;
}
}
}
}
// internal句を付与してに制限する(ついでにstaticにしておく)internalstatic Program
{
// public を追加するpublicstaticvoid Main(string[] args)
この場合同じアセンブリ (exe, dll) 内からしか呼べなくなるのですが、同じアセンブリから Main を再度呼ぶ事は性善説的にしない思うのでこれでも一応解決します。
というか、Program クラスが外部に公開されていてもいい事がひとつもない(脆弱性のレベルなので)Program クラスは外部公開しないほうがいいですね(Main メソッドだけ public にして internal を付けない場合、アセンブリ外から Main が呼べる状態になるので注意してください)
publicclass A
{
public A() => Console.WriteLine("A");
public A(string str) : this() => Console.WriteLine(str); // 自分のクラス内の他のコンストラクタ呼び出しを行う
}
var a = new A("str");
// > str// > A
基底クラスのコンストラクタの暗黙的な呼び出し
特に指定しない場合、暗黙的に基底クラスのデフォルトコンストラクターの呼び出しが連鎖が発生します。
例えば、A → B → C のように継承関係のあるクラスで特に指定しない場合デフォルトコンストラクターが暗黙で A → B → C の順で親から順に呼び出されます。
publicclass A
{
public A() => Console.WriteLine("A");
}
publicclass B : A
{
public B() => Console.WriteLine("B");
}
publicclass C : B
{
public C() => Console.WriteLine("C");
}
// こんな感じに呼び出すと出力が以下の通りになる
var c = new C();
// > A// > B// > C
publicclass A
{
public A() => Console.WriteLine("A");
}
publicclass B : A
{
public B() => Console.WriteLine("B-1");
public B(string b) => Console.WriteLine("B-2"); // 基底クラスのコンストラクタを指定しない
}
publicclass C : B
{
public C() => Console.WriteLine("C-1");
public C(string c) : base(c) => Console.WriteLine("C-2"); // 基底クラスのコンストラクタを指定
}
// この場合以下のような出力になる
C c = new C("str");
// > A// > B-2 // ★ここからデフォルトコンストラクター呼び出しに変わる// > C-2
コンストラクタ内での仮想メソッド呼び出し
C# はコンストラクタ内で仮想メソッドを呼び出しても正常に動作する(C++は違い保証があります)
仮想メソッドテーブル(vtable)は初期化が完了した状態でコンストラクターの処理に入ります。
publicclass A
{
publicvirtualvoid Foo() => Console.WriteLine("A");
}
publicclass B : A
{
publicoverridevoid Foo() => Console.WriteLine("B");
}
publicclass C : B
{
publicoverridevoid Foo() => Console.WriteLine("C");
public C() => this.Foo();
}
// コンストラクタ内で仮想メソッド呼び出ししても正常な動作が保証される
C c = new C();
// > C
A a = new C();
// > C
// record型の宣言例// → 書き換えできないstringのNameを持つクラスHogeが宣言できるpublic record Hoge(string Name);
// 複数のimmutableなフィールドを持つ方も簡単に宣言できる// → 書き換えできない3つのフィールドをもつ Barクラスが宣言できるpublic record Bar(string Name, int ID, int No);
publicstaticvoid Main(string[] args)
{
// テスト用データの取得
(Value a, Value b) = createValue_1();
// ★★★オブジェクトどうしの比較// → Target属性がついているメンバーを全部比較してくれるbool ret = a.Equals<Value>(b);
// ret = true
}
// テストデータ作成用のメソッドprivatestatic (Value a, Value b) createValue_1()
{
var sa = new SubValue() { PAS = "aaa", FAS = "bbb", };
sa.SetPBS(10);
sa.SetFBS(11);
var fa = new SubValue() { PAS = "ccc", FAS = "ddd", };
fa.SetPBS(12);
fa.SetFBS(13);
var a = new Value()
{
PA = sa,
PB = "ccc",
FA = fa,
FB = "ddd",
};
a.SetPC(14);
a.SetFC(15);
var sb = new SubValue() { PAS = "aaa", FAS = "bbb", };
sb.SetPBS(10);
sb.SetFBS(11);
var fb = new SubValue() { PAS = "ccc", FAS = "ddd", };
fb.SetPBS(12);
fb.SetFBS(13);
var b = new Value()
{
PA = sb,
PB = "ccc",
FA = fb,
FB = "ddd",
};
b.SetPC(14);
b.SetFC(15);
return (a, b);
}