仮想員に呼び出しのコンストラクタ
-
02-07-2019 - |
質問
もしかしたら警告から簡単に、ios、androidとmac用にc#約電話で仮想の会員からの私物のコンストラクタです。
なぜこうなるのか?
解決
時オブジェクトの文字はどうなるのinitializers走らの派生クラスの基底クラス、コンストラクタを基本クラスからの派生クラス見Eric Lippertのブログの詳細を理由としては、こ).
ものです。当期純物のないタイプの変更などにより構成されており、開始としての派生型の方法をしているとこの由来タイプです。この仮想メソッドの呼び出しは常に走行で最も由来タイプです。
リアルを組み合わせることによりこれら二つの事実に関する問題をする場合、その仮想メソッドの呼び出しでは、コンストラクタで最も由来タイプに継承階層であるという呼び出されるように、クラスのコンストラクタは実行されていますし、そのために時間がかかることが予想されに適した状態にしてこのメソッド呼び出されます。
この問題はもちろん、緩和されればマークをクラスとして密封確なものとするために、最も由来タイプに継承階層では、完全に安全で、仮想方法です。
他のヒント
のためにお答え、この質問:何以下のコードを印刷した場合に Child
オブジェクトのインスタンスを生成?
class Parent
{
public Parent()
{
DoSomething();
}
protected virtual void DoSomething()
{
}
}
class Child : Parent
{
private string foo;
public Child()
{
foo = "HELLO";
}
protected override void DoSomething()
{
Console.WriteLine(foo.ToLower()); //NullReferenceException!?!
}
}
その答えは実際には NullReferenceException
スローされ、 foo
はnullになります。 オブジェクトのベースのコンストラクタが呼び出される前に呼び出され、独自のコンストラクタ.を持つこと virtual
コオブジェクトのコンストラクタでは導入の可能性を継承すオブジェクトのコードが実行される前に全て初期化されます。
ルールのC#とは大きく異なることからJavaとC++.
きのコンストラクタのためのオブジェクトで、スレッドセーフで、C#、そのオブジェクトが完全に初期化されず"の構築")を通して、完全に由来タイプです。
namespace Demo
{
class A
{
public A()
{
System.Console.WriteLine("This is a {0},", this.GetType());
}
}
class B : A
{
}
// . . .
B b = new B(); // Output: "This is a Demo.B"
}
このお問い合わせいただいた場合の仮想関数からのコンストラクタの、問題解決へのオーバーライドBが提供する。
場合でも意図的に設置A、B、このような十分に理解の挙動の制してしまう可能性もあります。にショックです。と言いますバーチャルスクールと呼ばれる機能のコンストラクタでは、"知る"いま取り扱うダイヤルボタンとして適しています。そのログインパスワードをほかの誰かの判断に必要な定義、オーバーライド、仮想機能があります。突然のコンストラクタまでの呼び出しによる、非常に驚きます。
でない方が良いと仮想機能のコンストラクタから規則 は で異なるスレッドセーフで、C#、C++、Java.おのプログラマが知らないう期待する!
理由の警告は既述がどのように思を固定して傾きを解消し、警告?いシールのいずれかのクラスまたは仮想。
class B
{
protected virtual void Foo() { }
}
class A : B
{
public A()
{
Foo(); // warning here
}
}
できるシールのクラスA:
sealed class A : B
{
public A()
{
Foo(); // no warning
}
}
またはできるシール方法Foo:
class A : B
{
public A()
{
Foo(); // no warning
}
protected sealed override void Foo()
{
base.Foo();
}
}
クライアントまで、フルのC#ベースのクラスのコンストラクタ走 前 派生クラスのコンストラクタの者で、インスタンスの分野でその派生クラスを利用する場合がある可能-オーバーライドの仮想委員は初期化されません。
いことに注意してく 警告 に注意を払いを確認するようになっており、全てのです。が実際に使用ケースこのシナリオ、すぐに 書類の挙動 バーチャル会員では使用しないでインスタンスで宣言されているフィールドは導出クラスで以下のコンストラクタを呼び出します。
が書き回答は、上記の理由 な います。こちらえるかもしれません う いる(翻訳C#ら 実践的なオブジェクト指向デザインルビー によるSandi place d'armesとメッツ大聖堂、p.126).
ご注意 GetDependency()
なタインスタンス変数.このstaticの場合における静的メソッドできるvirtualなのです。
(公平であろうスマートなうことによ依存性注射器またはオブジェクトinitializers...)
public class MyClass
{
private IDependency _myDependency;
public MyClass(IDependency someValue = null)
{
_myDependency = someValue ?? GetDependency();
}
// If this were static, it could not be overridden
// as static methods cannot be virtual in C#.
protected virtual IDependency GetDependency()
{
return new SomeDependency();
}
}
public class MySubClass : MyClass
{
protected override IDependency GetDependency()
{
return new SomeOtherDependency();
}
}
public interface IDependency { }
public class SomeDependency : IDependency { }
public class SomeOtherDependency : IDependency { }
あり、一般的に悪い話を仮想メソッドはコンストラクタです。
この時点で、オブジェが完全に構築されていると思いますが、の不変量の予定の方法により合います。
いまでのコンストラクタの実行が完了し、オブジェクトはいないインスタンスを生成.他の会員によって参照されるの仮想関数がない場合initialised.C++では、ませんので、ご了承ください。はコンストラクタ this
ける静的タイプのコンストラクタでは、実際のダイナミック型のオブジェクトが作成されます。この仮想関数呼び出しがなさんが期待するということです。
おのコンストラクタがありその後、延長でアプリを作成できるソフトウェア)を呼び出すことができるコンストラクタのサブクラスでオーバーライドする仮想方法です。現在は、サブクラスの実装では機能が実施ベースのドラッグ&ドロップすると呼び出されます。なんと意味を呼び仮想関数がここに。
ただし、デザインを満たすLiskov代替原則として無害が行われることになります。うことになるのはなぜでの容認-警告、エラーとなります。
一つの重要な側面でのこの問いの答えいするものではない安心をベースクラスの呼び仮想委員から、そのコンストラクタ 場合はその派生クラスを期待することができるようになります.この場合、デザイナーの派生クラスを担当することを確保するための他の方法で作成する前に実行する工事が完了して行動するようなとしての良識としても下の状況です。例えば、C++/CLI、コンストラクタに包まれるコード通 Dispose
の一部を構成オブジェクトは失敗します。呼び出し Dispose
この場合に多くを防止するために必要な資源の漏えい、 Dispose
方法に準備が必要、そのオブジェクトにて実行されていないことが考えられ完全に構築された。
注意報-警報に関連することを改めて認識する仮想員がオーバーライドするに由来クラスです。その場合どのような親クラスのための仮想てることができます(下記のいずれかから選択または変更をオーバーの子です。の小さな例ではブロー機能再構成に成功しました。
の親クラス以下の試みの設定値をバーチャル会員、そのコンストラクタです。そのトリガを再急警報、参照コード:
public class Parent
{
public virtual object Obj{get;set;}
public Parent()
{
// Re-sharper warning: this is open to change from
// inheriting class overriding virtual member
this.Obj = new Object();
}
}
子のクラスはここをオーバーライドは、親ます。このプロパティませんでしたマ仮想のコンパイラのように警告することを隠財産の親クラスを提案し、これを追加したり、"新規"をキーワードであれば行っています。
public class Child: Parent
{
public Child():base()
{
this.Obj = "Something";
}
public override object Obj{get;set;}
}
最後に影響の出力例を以下に重要な虚偽表示の初期値設定による親クラスのコンストラクタです。この再鋭の試みに警告するように, 価値観の親クラスのコンストラクタを上書きされ子のクラスのコンストラクタと呼ばれる直後の親クラスのコンストラクタ.
public class Program
{
public static void Main()
{
var child = new Child();
// anything that is done on parent virtual member is destroyed
Console.WriteLine(child.Obj);
// Output: "Something"
}
}
注意墨以下に簡単に、ios、androidとmac用にc#のアドバイスとのクラス封入!●の場合は、モデルのEFコードでの仮想キーワードが無効に怠け者の負荷を出すことができます。
public **virtual** User User{ get; set; }
一つの重要な欠ビットは、何が正しいこの問題を解決するには?
として Greg説明, 根本問題ここでは、基底クラスのコンストラクタを呼び出す仮想委員前の由来クラスを構築した。
以下のコードから MSDNのコンストラクタ設計ガイドライン, に強みを発揮しています。
public class BadBaseClass
{
protected string state;
public BadBaseClass()
{
this.state = "BadBaseClass";
this.DisplayState();
}
public virtual void DisplayState()
{
}
}
public class DerivedFromBad : BadBaseClass
{
public DerivedFromBad()
{
this.state = "DerivedFromBad";
}
public override void DisplayState()
{
Console.WriteLine(this.state);
}
}
時の新しいインスタンス DerivedFromBad
作成の基底クラスのコンストラクタとの通話を DisplayState
示 BadBaseClass
った分野なのでは未更新の由来コンストラクタです。
public class Tester
{
public static void Main()
{
var bad = new DerivedFromBad();
}
}
改善実施を削除し、その仮想法から基底クラスのコンストラクタを使用して Initialize
方法。の新しいインスタンスを作成して DerivedFromBetter
表示の"DerivedFromBetter"
public class BetterBaseClass
{
protected string state;
public BetterBaseClass()
{
this.state = "BetterBaseClass";
this.Initialize();
}
public void Initialize()
{
this.DisplayState();
}
public virtual void DisplayState()
{
}
}
public class DerivedFromBetter : BetterBaseClass
{
public DerivedFromBetter()
{
this.state = "DerivedFromBetter";
}
public override void DisplayState()
{
Console.WriteLine(this.state);
}
}
もとC++とC#のです。C++では、オブジェクトが初期化されず、そのため、安全でない呼び出virutal関数内のコンストラクタです。クライアントまで、フルのC#クラスオブジェクトが作成したすべてのメンバーにゼロに初期化されます。で呼び出すことはできる仮想関数がコンストラクタになりますがアクセスメンバーがゼロになります。必要がない場合はアクセス会員では安全であることを知っている仮想関数がクライアントまで、フルのC#.
るだけで追加さんの表情が変わります。まず初期のフィールドを定義し、この問題は避けなければなりません。少なくとも以下のコードのように動作の魅力:
class Parent
{
public Parent()
{
DoSomething();
}
protected virtual void DoSomething()
{
}
}
class Child : Parent
{
private string foo = "HELLO";
public Child() { /*Originally foo initialized here. Removed.*/ }
protected override void DoSomething()
{
Console.WriteLine(foo.ToLower());
}
}
もう一つの興味深いことは簡単に、ios、androidとmac用にc#エラーになるので、できるだけ満足'によって以下のようなものであるダムにおいてしかし、これまで見てきたように多くの先でもいい話で仮想プロップ方法にctor.
public class ConfigManager
{
public virtual int MyPropOne { get; private set; }
public virtual string MyPropTwo { get; private set; }
public ConfigManager()
{
Setup();
}
private void Setup()
{
MyPropOne = 1;
MyPropTwo = "test";
}
}
私だけで追加Initialize()メソッドは、基底クラスを呼び出ることから由来のコンストラクタ.この方法は他の仮想/抽象メソッド/物件の後のすべてのコンストラクタは実行されているのは:)