AS#開発者向けのC#。 パート4:抽象クラスと関数

画像



AS3からC#への記事の翻訳、パート4:抽象クラスと関数



この記事では、AS3に類似物がないC#のニュアンスをようやく理解し始めます。 そして最初に、抽象クラスと抽象関数を検討します。 AS3では、実行時の段階で正しく機能するように回避策を考案する必要がありました。 しかし、C#はコンパイル時にステージを機能させる機会を提供します。今日はこれらのメソッドを分析します。





静的初期化子



しかし、その前に、以前の記事で説明し忘れていたAS3クラスの1つの機能、クラス初期化子、クラスコンストラクター、または静的コンストラクターとしても知られる静的初期化子についてお話したいと思います。 これは、クラスの静的フィールドを初期化する必要があるときに自動的に呼び出される関数です。 AS3での表示は次のとおりです。



class Person { private static var NEXT_ID:int; private var id:int; // static initializer: { NEXT_ID = 1; } // instance constructor function Person() { id = NEXT_ID++; } }
      
      







静的初期化子はあまり使用されません フィールドの宣言と初期化を同時に行うことができます。 例:



 private static var NEXT_ID:int = 1;
      
      







しかし、アプリケーションの動作のより複雑なロジックを実装する必要がある場合、それらは便利です。 いずれにせよ、C#での実装方法は次のとおりです。



 class Person { private static int NextID; private int id; // static initializer: static Person() { NextID = 1; } // instance constructor Person() { id = NextID++; } }
      
      







C#の静的初期化子は「静的コンストラクター」と呼ばれ、通常のコンストラクターと同様に機能しますが、クラスの個々のインスタンスではなく、クラス全体に対して機能します。 そのようなコンストラクターの構文は通常と同じですが、静的キーワードがコンストラクター宣言の先頭に追加されます。 これらのコンストラクターはアクセス修飾子(プライベート、パブリックなど)を持つことができず、着信パラメーターを受け入れることができません。



抽象クラス



次に、抽象クラスについて説明しましょう。これらは、直接インスタンス化できないクラスです。 抽象クラスのインスタンスを作成するには、抽象から継承する非抽象クラスを作成し、この非抽象クラスをインスタンス化する必要があります。 デフォルトでは、AS3にはコンパイル段階でそのような機能はありませんが、この制限を回避するためのかなり一般的な方法があります。



 class ExtrudedShape { private var depth:int; protected static const HIDDEN_KEY:Object = {}; function ExtrudedShape(ABSTRACT:Object, depth:int) { if (ABSTRACT != HIDDEN_KEY) { throw new ArgumentError("ExtrudedShape is an abstract class"); } this.depth = depth; } function get area(): int { return 0; } function get volume(): int { return depth * area; } }
      
      







この場合、ExtrudedShapeを直接作成することはまだ可能であり、同様のコードがコンパイルされます:



 var shape:ExtrudedShape = new ExtrudedShape(null, 3);
      
      







ただし、実行段階では、最初の引数の検証が機能し、ArgumentErrorエラーが発生するため、ExtrudedShapeインスタンスは作成されません。 これは、ExtrudedShapeから継承されていないクラスが保護された定数HIDDEN_KEYにアクセスできないという事実によるものですが、同時に、ExtrudedShapeから派生したクラスは親コンストラクターに渡すためにこの変数にアクセスできます。



 class ExtrudedCircle extends ExtrudedShape { function ExtrudedCircle(depth:int) { super(HIDDEN_KEY, depth); } }
      
      







これは、再生段階で抽象クラスを実装するための非常に効率的な方法ですが、C#はコンパイル段階ですべての作業を実行する機能を提供します。



 abstract class ExtrudedShape { private int depth { get; private set; } ExtrudedShape(int depth) { this.depth = depth; } int Area { get { return 0; } } int Volume { get { return depth * Area; } } }
      
      







クラスの先頭での抽象キーワードの使用に注意してください。 これは、コンパイラがこのクラスの直接作成を許可しないことを意味します。 このアプローチでは、AS3で必要な追加のコードや「回避策」は必要ありません(派生クラスはHIDDEN_KEYを使用する必要がなく、初期化と宣言は他のクラスとまったく同じに見えます)。



 class ExtrudedCircle : ExtrudedShape { ExtrudedCircle(int depth) : base(depth) { } }
      
      







抽象関数



抽象関数は、特定の関数の実装を子クラスで再定義する必要があることを示す必要がある場合に使用されます。 繰り返しますが、AS3にはコンパイル段階でこれを実装する方法はありませんが、抽象クラスの場合のように、この制限を回避する方法があります。



 class ExtrudedShape { private var depth:int; protected static const HIDDEN_KEY:Object = {}; function ExtrudedShape(ABSTRACT:Object, depth:int) { if (ABSTRACT != HIDDEN_KEY) { throw new ArgumentError("ExtrudedShape is an abstract class"); } this.depth = depth; } function get area(): int { throw new Error("'get area' is an abstract function"); return 0; } function get volume(): int { return depth * area; } }
      
      







この例では、ExtrudedShapeクラスはエリア取得機能の機能を実装していません。これは、ExtrudedShapeクラスが何も知らないためです。 このバージョンでは、ExtrudedShapeクラスのget area関数を呼び出すとエラーが発生します。 このアプローチにより、再生段階で抽象関数を実装できますが、コンパイル段階では実装できません。 たとえば、次のコードはget area関数を実装せずに正常にコンパイルされます。



 class ExtrudedCircle extends ExtrudedShape { }
      
      







代わりに、C#では、単にabstractキーワードを使用できます。



 abstract class ExtrudedShape { private int depth { get; private set; } ExtrudedShape(int depth) { this.depth = depth; } abstract public int Area { get; } int Volume { get { return depth * Area; } } } class ExtrudedCircle : ExtrudedShape { private int area; override int Area { get { return area; } } }
      
      







同じキーワードが通常の関数に使用されます(ゲッター/セッターではありません):



 abstract class GameEntity { abstract void TakeDamage(int damage); } class Enemy : GameEntity { int health; override void TakeDamage(int damage) { health -= damage; } }
      
      







今日は、抽象クラスと関数、および静的イニシャライザについて説明しました。 統合するために、C#とAS3でこの機能を実装する機能を比較してみましょう。



 //////// // C# // //////// // Abstract class abstract class GameEntity { private static int NextID; protected int health; int id; static GameEntity() { NextID = 1; } GameEntity(int health) { this.health = health; this.id = NextID++; } // Abstract property bool Friendly { abstract get; } // Abstract function abstract void TakeDamage(int amount) { } } // Non-abstract ("concrete") class class Enemy : GameEntity { Enemy(int health) : base(health) { } // Implemented abstract property override bool Friendly { get { return false; } } // Implemented abstract function override void TakeDamage(int amount) { health -= amount; } }
      
      





 ///////// // AS3 // ///////// // Abstract class - only enforced at run-time class GameEntity { private static var NEXT_ID:int; protected static const HIDDEN_KEY:Object = {}; protected var health:int; var id:int; // Static initializer { NEXT_ID = 1; } function GameEntity(ABSTRACT:Object, health:int) { if (ABSTRACT != HIDDEN_KEY) { throw new ArgumentError("GameEntity is abstract"); } this.health = health; this.id = NEXT_ID++; } // Abstract property/getter - only enforced at run-time function get friendly(): Boolean { throw new Error("'get friendly' is abstract"); return false; } // Abstract function - only enforced at run-time function takeDamage(amount:int): void { throw new Error("takeDamage is abstract"); } } // Non-abstract ("concrete") class class Enemy extends GameEntity { function Enemy(health:int) { super(HIDDEN_KEY, health); } // Implemented abstract property override function get friendly(): Boolean { return false; } // Implemented abstract function override function takeDamage(amount:int): void { health -= amount; } }
      
      









次の記事では、デストラクタ、コンストラクターのオーバーロードを扱うときのトリックなどについて説明します。



私たちと一緒にいてください!



All Articles