<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Flashist</title>
	<atom:link href="https://flashist.ru/feed/" rel="self" type="application/rss+xml" />
	<link>https://flashist.ru</link>
	<description>Codegame every day!</description>
	<lastBuildDate>Mon, 02 Feb 2015 13:56:02 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.2.39</generator>
	<item>
		<title>С# для AS3 разработчиков. Часть 5: Статические классы, Деструкторы и Приёмы для работы с конструкторами</title>
		<link>https://flashist.ru/2015/02/02/c-sharp-for-as3-developers-part-5-static-classes-destructors-constructor-tricks/</link>
		<comments>https://flashist.ru/2015/02/02/c-sharp-for-as3-developers-part-5-static-classes-destructors-constructor-tricks/#comments</comments>
		<pubDate>Mon, 02 Feb 2015 13:56:02 +0000</pubDate>
		<dc:creator><![CDATA[Flashist]]></dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# для AS3 разработчиков]]></category>
		<category><![CDATA[Gamedev]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://flashist.ru/?p=104</guid>
		<description><![CDATA[<p>Перевод статьи From AS3 to C#, Part 5: Static Classes, Destructors, and Constructor Tricks В прошлый раз мы с&#8230;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/02/02/c-sharp-for-as3-developers-part-5-static-classes-destructors-constructor-tricks/">С# для AS3 разработчиков. Часть 5: Статические классы, Деструкторы и Приёмы для работы с конструкторами</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p><img class="alignnone" src="https://img-fotki.yandex.ru/get/16130/29305053.0/0_a3312_13a3dd70_orig" alt="" width="600" height="300" /></p>
<p><em>Перевод статьи <a href="http://jacksondunstan.com/articles/2737">From AS3 to C#, Part 5: Static Classes, Destructors, and Constructor Tricks</a></em></p>
<p>В прошлый раз мы с вами рассмотрели абстрактные классы, но уже на этой неделе мы обсудим даже более абстрактный тип классов (чем абстрактные классы): статические классы. Так же, мы рассмотрим анти-конструкторы <strong>C#</strong>, которые более известны, как &#8220;деструкторы&#8221;, и, в дополнение ко всему, мы рассмотрим некоторые забавные трюки при работе с конструкторами классов.</p>
<p><span id="more-104"></span></p>
<h4> </h4>
<h4>Статические классы</h4>
<p>Давайте начнём сегодняшнюю статью с &#8220;даже более абстрактных&#8221; классов: статических классов. Работая с абстрактными классами, вы всё ещё можете расширять их и создавать экземпляры дочерних классов:</p>
<p></p><pre class="crayon-plain-tag">abstract class Shape
{
}
 
class Square : Shape // legal
{
}
 
new Shape(); // illegal
new Square(); // legal</pre><p></p>
<p>Работая со статическими классами, вы не можете ни инстанциировать, ни наследовать их. Вы никогда не сможете создать экземпляр подобного класса:</p>
<p></p><pre class="crayon-plain-tag">static class Shape
{
}
 
class Square : Shape // illegal
{
}
 
new Shape(); // illegal
new Square(); // illegal</pre><p></p>
<p>Но для чего вообще могут понадобиться подобные классы? Подобные классы могут быть хорошим местом для хранения статических функций, полей и свойств. И, так как вы не можете создавать экземпляры подобных классов, в них запрещено использование не статических полей любых типов данных. Конструкторы экземпляров класса так же запрещены, т.к. класс автоматически приравнивается к <strong>sealed</strong> классам. Довольно популярный пример использования подобных классов &#8211; класс <strong>Math</strong>. Вам вряд ли когда-либо нужно будет создать экземпляр этого класса, но внутри него содержится большое количество полезных статических функций (например <strong>Abs</strong>) и полей (например <strong>PI</strong>). Вот, как может выглядеть реализация подобного класса:</p>
<p></p><pre class="crayon-plain-tag">public static class Math
{
    // remember that 'const' is automatically static
    // also, this would surely have more precision
    public const double PI = 3.1415926;
 
    public static double Abs(double value)
    {
        return value &gt;= 0 ? value : -value;
    }
}
 
new Math(); // illegal</pre><p></p>
<p>В <strong>AS3</strong> по-умолчанию нет поддержки статических классов на этапе компиляции, но вы можете обойти это ограничение, используя проверки на этапе проигрывания (<strong>run-time</strong>). Всё, что вам нужно будет сделать &#8211; это объявить класс, как <strong>final</strong>, и всегда бросать ошибку в конструкторе этого класса:</p>
<p></p><pre class="crayon-plain-tag">public final class Math
{
    public static const PI:Number = 3.1415926;
 
    public function Math()
    {
        throw new Error("Math is static");
    }    
 
    public static function abs(value:Number): Number
    {
        return value &gt;= 0 ? value : -value;
    }
}
 
new Math(); // legal, but throws an exception</pre><p></p>
<p>&nbsp;</p>
<h4>Деструкторы</h4>
<p>Следующим пунктом в сегодняшней программе идут деструкторы, которые являются &#8220;анти-конструкторами&#8221;, потому что они отвечают за уничтожение класса, а не за его создание, как в случае с обычными конструкторами. Деструкторы вызываются сборщиками мусора (<strong>Garbage Collector</strong>) непосредственно перед тем, как объект освобождает занимаемую им память. Вот, как они выглядят:</p>
<p></p><pre class="crayon-plain-tag">class TemporaryFile
{
    ~TemporaryFile()
    {
        // cleanup code goes here
    }
}</pre><p></p>
<p>Для создания деструктора, достаточно добавить ~ к имени класса. Деструктор может быть только один, и с ним нельзя использовать модификаторы доступа. Обычно, необходимости в создании деструкторов нет, но в некоторых случаях они могут быть полезными, в качестве способа очистки ресурсов после использования класса. В примере ниже деструктор используется для удаления из операционной системы временного файла, который в другом случае не будет удалён, т.к. <strong>GC</strong> никогда не сделает этого:</p>
<p></p><pre class="crayon-plain-tag">using System.IO;
 
class TemporaryFile
{
    public String Path { get; private set; }
 
    TemporaryFile(String path)
    {
        Path = path;
        File.Create(path);
    }
 
    ~TemporaryFile()
    {
        File.Delete(Path);
    }
}
 
// Create the temporary file
TemporaryFile temp = new TemporaryFile("/path/to/temp/file");
 
// ... use the temporary file
 
// Remove the last reference to the TemporaryFile instance
// GC will now collect temp, call the destructor, and delete the file
temp = null;</pre><p></p>
<p>&nbsp;</p>
<p>В данном примере класс <strong>TemporaryFile</strong> создаёт файл в конструкторе экземпляра класса, и удаляет файл, когда на экземпляр класса нет ссылок и класс готов быть собранным <strong>GC</strong>, чтобы освободить память. В <strong>AS3</strong> нет функций, которые бы вызывались, когда экземпляр класса готов быть собранным <strong>GC</strong>. Обычно, чтобы реализовать подобное поведение, необходимо вручную создавать и вызывать &#8220;псевдо-деструкторы&#8221; (обычно их называют <strong>dispose</strong> или <strong>destroy</strong>):</p>
<p></p><pre class="crayon-plain-tag">import flash.filesystem;
 
class TemporaryFile
{
    private var _path:String;
    public function get path(): String { return _path; }
    public function set path(p:String): void { _path = p; }
 
    private var _file:File;
 
    function TemporaryFile(path:String)
    {
        _path = path;
        _file = new File(path);
        var stream:FileStream = new FileStream();
        stream.open(_file, FileMode.WRITE);
    }
 
    function dispose(): void
    {
        _file.deleteFile();
    }
}
 
// Create the temporary file
var temp:TemporaryFile = new TemporaryFile("/path/to/temp/file");
 
// ... use the temporary file
 
// Manually call dispose() to delete the temporary file
temp.dispose();
 
// Remove the last reference to the TemporaryFile instance
// GC will now collect temp
temp = null;</pre><p></p>
<p>&nbsp;</p>
<h4>Трюки при работе с конструкторами</h4>
<p>Последней темой на сегодня будут трюки при работе с конструкторами. Мы уже разбирали способ вызова конструктора базового класса, используя ключевое слово <strong>base</strong> (аналогично использованию ключевого слова <strong>super</strong> в <strong>AS3</strong>):</p>
<p></p><pre class="crayon-plain-tag">class Polygon
{
    Polygon(int numSides)
    {
    }
}
class Triangle : Polygon
{
    Triangle()
        : base(3) // call the Polygon constructor
    {
    }
}</pre><p></p>
<p>Так же, мы рассматривали возможность создания более чем одного конструктора, используя &#8220;перегрузку&#8221;:</p>
<p></p><pre class="crayon-plain-tag">class Vector3
{
    double X;
    double Y;
    double Z;
 
    Vector3()
    {
        X = 0;
        Y = 0;
        Z = 0;
    }
 
    Vector3(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }
 
    Vector3(Vector3 vec)
    {
        X = vec.X;
        Y = vec.Y;
        Z = vec.Z;
    }
}
 
Vector3 v1 = new Vector3();        // (0, 0, 0)
Vector3 v2 = new Vector3(1, 2, 3); // (1, 2, 3)
Vector3 v3 = new Vector3(v2);      // (1, 2, 3)</pre><p></p>
<p>&nbsp;</p>
<p>Обычно этот способ приводит к дублированию кода внутри конструкторов. Но, т.к. версия конструктора , которая принимает 3 параметра наиболее общая из всех, то можно просто вызывать её из 2 других конструкторов:</p>
<p></p><pre class="crayon-plain-tag">class Vector3
{
    double X;
    double Y;
    double Z;
 
    Vector3()
        : this(0, 0, 0)
    {
    }
 
    Vector3(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }
 
    Vector3(Vector3 vec)
        : this(vec.X, vec.Y, vec.Z)
    {
    }
}
 
Vector3 v1 = new Vector3();        // (0, 0, 0)
Vector3 v2 = new Vector3(1, 2, 3); // (1, 2, 3)
Vector3 v3 = new Vector3(v2);      // (1, 2, 3)</pre><p></p>
<p>Мы можем использовать <strong>this()</strong> для вызова других конструкторов в рамках нашего класса (по аналогии с <strong>base()</strong>, что позволяло вызывать конструктор родительского класса). И снова, в <strong>AS3</strong> не было подобного функционала по-умолчанию, поэтому его приходилось &#8220;эмулировать&#8221; с помощью статических псевдо-конструкторов, которые вызывали функции наподобие <strong>init</strong>/<strong>setup</strong>/<strong>contruct</strong> у создаваемых объектов:</p>
<p></p><pre class="crayon-plain-tag">class Vector3
{
    var x:Number;
    var y:Number;
    var z:Number;
 
    function Vector3()
    {
        init(0, 0, 0);
    }
 
    // pseudo-constructor
    static function fromComponents(x:Number, y:Number, z:Number)
    {
        var ret:Vector3 = new Vector3();
        ret.init(x, y, z);
        return ret;
    }
 
    // pseudo-constructor    
    static function fromVector(Vector3 vec)
    {
        var ret:Vector3 = new Vector3();
        ret.init(vec.X, vec.Y, vec.Z);
        return ret;
    }
 
    // helper function
    function init(x:Number, y:Number, z:Number): void
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}
 
var v1:Vector3 = new Vector3();                   // (0, 0, 0)
var v2:Vector3 = Vector3.fromComponents(1, 2, 3); // (1, 2, 3)
var v3:Vector3 = Vector3.fromVector(v2);          // (1, 2, 3)</pre><p></p>
<p>На этом мы сегодня закончим и, как обычно, в завершении статьи мы сравним описанные сегодня особенности работы с <strong>C#</strong> и <strong>AS3</strong>:</p>
<table>
<tbody>
<tr>
<td>
<pre class="crayon-plain-tag">////////
// C# //
////////
 
// Static class
public static class MathHelpers
{
	public const double DegreesToRadians = Math.PI / 180.0;
	public const double RadiansToDegrees = 180.0 / Math.PI;
 
 
 
 
 
 
	public static double ConvertDegreesToRadians(double degrees)
	{
		return degrees * DegreesToRadians;
	}
 
	public static double ConvertRadiansToDegrees(double radians)
	{
		return radians * RadiansToDegrees;
	}
}
 
// Class with a destructor
class TemporaryFile
{
	public String Path { get; private set; }
 
 
 
 
 
 
 
 
 
 
 
	TemporaryFile(String path)
	{
		Path = path;
		File.Create(path);
	}
 
 
 
	// Destructor
	~TemporaryFile()
	{
		File.Delete(Path);
	}
}
 
// Class with shared constructor code
class Vector3
{
	double X;
	double Y;
	double Z;
 
	Vector3()
		: this(0, 0, 0)
	{
	}
 
	// shared constructor code
	Vector3(double x, double y, double z)
	{
		X = x;
		Y = y;
		Z = z;
	}
 
	Vector3(Vector3 vec)
		: this(vec.X, vec.Y, vec.Z)
	{
	}
 
 
 
 
 
 
 
 
 
 
}</pre>
</td>
<td>
<pre class="crayon-plain-tag">/////////
// AS3 //
/////////
 
// Static class - runtime only
public class MathHelpers
{
    public static const DegreesToRadians:Number = Math.PI / 180.0;
    public static const RadiansToDegrees:Number = 180.0 / Math.PI;
 
    public function MathHelpers()
    {
        throw new Error("MathHelpers is static");
    }
 
    public static function ConvertDegreesToRadians(degrees:Number): Number
    {
        return degrees * DegreesToRadians;
    }
 
    public static function ConvertRadiansToDegrees(radians:Number): Number
    {
        return radians * RadiansToDegrees;
    }
}
 
// Class with a destructor
class TemporaryFile
{
    private var _path:String;
    public function get path(): String
    {
        return _path;
    }
    public function set path(p:String): void
    {
        _path = p;
    }
 
    private var _file:File;
 
    function TemporaryFile(path:String)
    {
        _path = path;
        _file = new File(path);
        var stream:FileStream = new FileStream();
        stream.open(_file, FileMode.WRITE);
    }
 
    // Destructor - must be called manually
    function dispose(): void
    {
        _file.deleteFile();
    }
}
 
// Class with shared constructor code
class Vector3
{
    var x:Number;
    var y:Number;
    var z:Number;
 
    function Vector3()
    {
        init(0, 0, 0);
    }
 
 
    static function fromComponents(x:Number, y:Number, z:Number)
    {
        var ret:Vector3 = new Vector3();
        ret.init(x, y, z);
            return ret;
    }
 
    static function fromVector(Vector3 vec)
    {
        var ret:Vector3 = new Vector3();
        ret.init(vec.X, vec.Y, vec.Z);
            return ret;
    }
 
    // shared constructor code - helper function required
    function init(x:Number, y:Number, z:Number): void
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}</pre>
</td>
</tr>
</tbody>
</table>
<p>В следующей статье мы разберём новые особенности <strong>C#</strong>, которых не было в <strong>AS3</strong>!</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/02/02/c-sharp-for-as3-developers-part-5-static-classes-destructors-constructor-tricks/">С# для AS3 разработчиков. Часть 5: Статические классы, Деструкторы и Приёмы для работы с конструкторами</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://flashist.ru/2015/02/02/c-sharp-for-as3-developers-part-5-static-classes-destructors-constructor-tricks/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>С# для AS3 разработчиков. Часть 4: Абстрактные классы и функции</title>
		<link>https://flashist.ru/2015/01/27/c-sharp-for-as3-developers-part-4-abstract-classes-and-functions/</link>
		<comments>https://flashist.ru/2015/01/27/c-sharp-for-as3-developers-part-4-abstract-classes-and-functions/#comments</comments>
		<pubDate>Tue, 27 Jan 2015 13:35:16 +0000</pubDate>
		<dc:creator><![CDATA[Flashist]]></dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# для AS3 разработчиков]]></category>
		<category><![CDATA[Gamedev]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://flashist.ru/?p=96</guid>
		<description><![CDATA[<p>Перевод статьи From AS3 to C#, Part 4: Abstract Classes and Functions В этой статье мы наконец-то начнём разбираться&#8230;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/01/27/c-sharp-for-as3-developers-part-4-abstract-classes-and-functions/">С# для AS3 разработчиков. Часть 4: Абстрактные классы и функции</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p><img class="alignnone" src="https://img-fotki.yandex.ru/get/52/29305053.0/0_a2d21_465936e_orig" alt="" width="600" height="300" /></p>
<p><em>Перевод статьи </em><a href="http://jacksondunstan.com/articles/2720">From AS3 to C#, Part 4: Abstract Classes and Functions</a></p>
<p>В этой статье мы наконец-то начнём разбираться в нюансах <strong>C#</strong>, аналогов которых нет в <strong>AS3</strong>. И первым делом мы рассмотрим абстрактные классы и функции. В <strong>AS3</strong> необходимо было придумывать обходные пути, чтобы они работали правильно на этапе исполнения (<strong>run-time</strong>). Но <strong>C#</strong> предоставляет возможность заставить их работать на этапе компиляции (<strong>compile-time</strong>), и сегодня мы разберём эти способы.</p>
<p><span id="more-96"></span></p>
<h4> </h4>
<h4>Статические инициализаторы</h4>
<p>Но, до этого, я бы хотел рассказать об одной особенности <strong>AS3</strong> классов, о которой я забыл рассказать в предыдущих статьях: статические инициализаторы (<strong>static initializers</strong>), так же известные как инициализаторы класса, конструкторы класса или статические конструкторы. Это &#8211; функция, которая будет вызвана автоматически, когда статические поля класса должны быть инициализированы. Вот, как это выглядело в <strong>AS3</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private static var NEXT_ID:int;
    private var id:int;
 
    // static initializer:
    {
        NEXT_ID = 1;
    }
 
    // instance constructor
    function Person()
    {
        id = NEXT_ID++;
    }
}</pre><p></p>
<p>Статические инициализаторы используются не часто, т.к. у нас есть возможность объявлять и инициализировать поля в одно и то же время. Например:</p>
<p></p><pre class="crayon-plain-tag">private static var NEXT_ID:int = 1;</pre><p></p>
<p>Но, они могут быть полезны, если необходимо реализовать более сложную логику поведения приложения. В любом случае, вот, как это может быть реализовано в <strong>C#</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private static int NextID;
    private int id;
 
    // static initializer:
    static Person()
    {
        NextID = 1;
    }
 
    // instance constructor
    Person()
    {
        id = NextID++;
    }
}</pre><p></p>
<p>Статические инициализаторы в <strong>C#</strong> называются &#8220;статическими конструкторами&#8221; и работают по аналогии с обычными конструкторами, но не для отдельных экземпляров классов, а для всего класса целиком. Синтаксис подобных конструкторов совпадает с обычными, но в начале объявления конструктора добавляется ключевое слово <strong>static</strong>. У данных конструкторов не может быть модификаторов доступа (<strong>private</strong>, <strong>public</strong> и т.п.) и они не могут принимать входящие параметры.</p>
<p>&nbsp;</p>
<h4>Абстрактные классы</h4>
<p>А теперь, давайте поговорим об абстрактных классах: это &#8211; такие классы, которые не могут быть инстанциированы напрямую. Чтобы создать экземпляр абстрактного класса, вам необходимо будет создать не абстрактный класс, который будет наследоваться от абстрактного, и инстанциировать этот не абстрактный класс. По-умолчанию в <strong>AS3</strong> нет подобного функционала на этапе компиляции, но, существует довольно популярный способ обойти это ограничение:</p>
<p></p><pre class="crayon-plain-tag">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;
    }
}</pre><p></p>
<p>В данном случае создание <strong>ExtrudedShape</strong> напрямую всё ещё возможно, и подобный код будет компилироваться:</p>
<p></p><pre class="crayon-plain-tag">var shape:ExtrudedShape = new ExtrudedShape(null, 3);</pre><p></p>
<p>Но на этапе исполнения сработает проверка первого аргумента, что повлечёт за собой появление ошибки <strong>ArgumentError</strong>, и экземпляр <strong>ExtrudedShape</strong> не будет создан. Это произойдёт из-за того, что классы, не унаследованные от <strong>ExtrudedShape</strong> не будут иметь доступа к <strong>protected</strong> константе <strong>HIDDEN_KEY</strong>, но, в то же время, классы-производные от <strong>ExtrudedShape</strong> смогут обращаться к этой переменной для передачи в родительский конструктор:</p>
<p></p><pre class="crayon-plain-tag">class ExtrudedCircle extends ExtrudedShape
{
    function ExtrudedCircle(depth:int)
    {
        super(HIDDEN_KEY, depth);
    }
}</pre><p></p>
<p>Это &#8211; довольно эффективный способ реализации абстрактных классов на этапе проигрывания, но <strong>C#</strong> предоставляет возможность сделать всю работу на этапе компиляции:</p>
<p></p><pre class="crayon-plain-tag">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; }
    }
}</pre><p></p>
<p>Обратите внимание на использование ключевого слова <strong>abstract</strong> вначале класса. Оно означает, что компилятор не должен разрешать создание данного класса напрямую. Данный подход не требует дополнительного кода или &#8220;обходных путей&#8221;, которые необходимы в <strong>AS3</strong> (производным классам не нужно использовать <strong>HIDDEN_KEY</strong>, а их инициализация и объявление выглядит точно так же, как и у других классов):</p>
<p></p><pre class="crayon-plain-tag">class ExtrudedCircle : ExtrudedShape
{
    ExtrudedCircle(int depth)
        : base(depth)
    {
    }
}</pre><p></p>
<p>&nbsp;</p>
<h4>Абстрактные функции</h4>
<p>Абстрактные функции используются в тех случаях, когда необходимо указать, что реализация определённой функции, обязательно должна быть переопределена в дочернем классе. И снова, в <strong>AS3</strong> нет возможности реализовать подобное на этапе компиляции, но, как и в случае с абстрактными классами, существует способ обойти это ограничение:</p>
<p></p><pre class="crayon-plain-tag">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;
    }
}</pre><p></p>
<p>В данном примере класс <strong>ExtrudedShape</strong> не реализует функционал функции <strong>get area</strong>, так как он ничего не знает о ней. В данной версии, обращение к функции <strong>get area</strong> класса <strong>ExtrudedShape</strong> вызовет ошибку. Данный подход позволяет реализовать абстрактные функции на этапе воспроизведения, но не на этапе компиляции. Например, следующий код будет успешно компилироваться без реализации функции <strong>get area</strong>:</p>
<p></p><pre class="crayon-plain-tag">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; }
    }
}</pre><p></p>
<p>Это же ключевое слово будет использоваться для обычных функций (не геттер/сеттер):</p>
<p></p><pre class="crayon-plain-tag">abstract class GameEntity
{
    abstract void TakeDamage(int damage);
}
 
class Enemy : GameEntity
{
    int health;
 
    override void TakeDamage(int damage)
    {
        health -= damage;
    }
}</pre><p></p>
<p>Сегодня мы обсудили абстрактные классы и функции, а так же статические инициализаторы. Для закрепления, давайте сравним особенности реализации этого функционала в <strong>C#</strong> и <strong>AS3</strong>:</p>
<table>
<tbody>
<tr>
<td>
<pre class="crayon-plain-tag">////////
// 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;
    }
}</pre>
</td>
<td>
<pre class="crayon-plain-tag">/////////
// 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;
    }
}</pre>
</td>
</tr>
</tbody>
</table>
<p>В следующей статье мы поговорим о деструкторах, трюках при работе с перегрузкой конструкторов и о многом другом.</p>
<p>Оставайтесь с нами!</p>
<p>&nbsp;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/01/27/c-sharp-for-as3-developers-part-4-abstract-classes-and-functions/">С# для AS3 разработчиков. Часть 4: Абстрактные классы и функции</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://flashist.ru/2015/01/27/c-sharp-for-as3-developers-part-4-abstract-classes-and-functions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>С# для AS3 разработчиков. Часть 3: get, set, sealed, using, const, readonly</title>
		<link>https://flashist.ru/2015/01/26/c-sharp-for-as3-developers-part-3-get-set-sealed-using-const-readonly/</link>
		<comments>https://flashist.ru/2015/01/26/c-sharp-for-as3-developers-part-3-get-set-sealed-using-const-readonly/#comments</comments>
		<pubDate>Mon, 26 Jan 2015 07:29:27 +0000</pubDate>
		<dc:creator><![CDATA[Flashist]]></dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# для AS3 разработчиков]]></category>
		<category><![CDATA[Gamedev]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://flashist.ru/?p=71</guid>
		<description><![CDATA[<p>  Перевод статьи From AS3 to C#, Part 3: AS3 Class Parity Сегодня мы закончим разбираться с классами в&#8230;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/01/26/c-sharp-for-as3-developers-part-3-get-set-sealed-using-const-readonly/">С# для AS3 разработчиков. Часть 3: get, set, sealed, using, const, readonly</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p> <img class="alignnone" src="https://img-fotki.yandex.ru/get/15485/29305053.0/0_a2cc1_91c194c0_orig" alt="" width="600" height="300" /></p>
<p><em>Перевод статьи <a href="http://jacksondunstan.com/articles/2714">From AS3 to C#, Part 3: AS3 Class Parity</a></em></p>
<p>Сегодня мы закончим разбираться с классами в <strong>C#</strong> (с точки зрения <strong>AS3</strong> разработчика) и подготовимся к следующей статье, в которой мы сможем познакомиться с понятиями, аналогов которых нет в <strong>AS3</strong>. В текущей статье мы рассмотрим способ реализации:<br />&#8211; геттеров/сеттеров (<strong>getter</strong>/<strong>setter</strong>)<br />&#8211; функций и классов, которые нельзя переопределять/наследовать (<strong>final</strong>)<br />&#8211; констант<br />&#8211; пакетов</p>
<p><span id="more-71"></span></p>
<h4> </h4>
<h4>Get/Set функции</h4>
<p>Давайте начнём с геттеров и сеттеров. Чтобы освежить память, вот, как они выглядели в <strong>AS3</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private var _name:String;
    public function get name(): String
    {
        return _name;
    }
    public function set name(n:String): void
    {
        _name = n;
    }
}</pre><p></p>
<p>А вот, эквивалент в <strong>С#</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private String _name;
    public String Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }
}</pre><p></p>
<p>Как мы можем увидеть, в <strong>C#</strong>, вместо объявления 2 функций, геттер и сеттер объявлены в виде единственной переменной. Правда, эта переменная не заканчивается точкой с запятой (<strong>;</strong>), а содержит блок в виде фигурных скобок, внутри которого есть 2 части: <strong>get{}</strong> и <strong>set{}</strong>. Эти части являются геттер и сеттер функциями. Внутри сеттера у вас будет доступ к новому ключевому слову <strong>value</strong>, оно представляет собой значение, которое должно быть установлено и вам не нужно объявлять его, как это приходилось делать в <strong>AS3</strong>. Если не брать в расчёт это отличие в синтаксисе, геттеры и сеттеры работают одинаково в <strong>C#</strong> и <strong>AS3</strong>.</p>
<p><strong>C#</strong> предоставляет возможность использовать сокращённую запись для подобных функций, позволяя избежать написание лишнего кода для простых функций:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    public String Name { get; set; }
}</pre><p></p>
<p>Использование этой конструкции автоматически создаст переменную <strong>_name</strong> и геттер/сеттер функции, как в примере выше. Но что, если вам не нужна функция-сеттер? Просто уберите её:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    public String Name { get; }
}</pre><p></p>
<p>Скорее всего, вам необходимо будет, как минимум, предоставить возможность классу <strong>Person</strong> устанавливать значения этой переменной. Для этого сеттер может быть объявлен <strong>private</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    public String Name { get; private set; }
}</pre><p></p>
<p>И ещё, немного терминологии <strong>C#</strong>: поля класса, у которых есть <strong>get</strong> и/или <strong>set</strong> функции (<strong>Name</strong>), называются &#8220;свойства&#8221;. Переменные, которые используются для хранения этих данных (<strong>_name</strong>), называются &#8220;вспомогательные поля&#8221;.</p>
<p>&nbsp;</p>
<h4>Final/sealed функции</h4>
<p>А теперь, давайте поговорим о <strong>final</strong> функциях, которые не могут быть переопределены (<strong>AS3</strong>):</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    final function print(): void
    {
        trace("I'm a Person");
    }
}
 
class MyPerson extends Person
{
    // illegal
    override function print(): void
    {
        trace("I'm not just a Person, I'm a MyPerson too");
    }
}</pre><p></p>
<p><strong>С#</strong> предоставляет идентичный функционал, используя слово <strong>sealed</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    sealed void Print()
    {
        Debug.Log("I'm a Person");
    }
}
 
class MyPerson extends Person
{
    // illegal
    override void Print()
    {
        Debug.Log("I'm not just a Person, I'm a MyPerson too");
    }
}</pre><p></p>
<p>&nbsp;</p>
<h4>Пакеты и namespace</h4>
<p>Пакеты в <strong>AS3</strong>:</p>
<p></p><pre class="crayon-plain-tag">package com.jacksondunstan.examples
{
    class Person
    {
    }
}</pre><p></p>
<p>В <strong>C#</strong>, пакеты называются <strong>namespace</strong>, вот и всё:</p>
<p></p><pre class="crayon-plain-tag">namespace com.jacksondunstan.examples
{
    class Person
    {
    }
}</pre><p></p>
<p>Чтобы получить доступ к пакету внутри <strong>.as</strong> файла, вы можете импортировать пакет:</p>
<p></p><pre class="crayon-plain-tag">import com.jacksondunstan.examples;
 
class Printer
{
    function print(person:Person): void
    {
        trace("person has name: " + person.name);
    }
}</pre><p></p>
<p>В <strong>C#</strong> вы используете ключевое слово <strong>using</strong> для <strong>namespace</strong>:</p>
<p></p><pre class="crayon-plain-tag">using com.jacksondunstan.examples;
 
class Printer
{
    void Print(Person person)
    {
        Debug.Log("person has name: " + person.name);
    }
}</pre><p></p>
<p>&nbsp;</p>
<h4>Константы и readonly переменные</h4>
<p>И напоследок, давайте поговорим о константах. Вот, как в <strong>AS3</strong> может быть создано поле, которое нельзя изменить после объявления:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private static const MIN_TEEN_AGE:int = 13;
    private static const MAX_TEEN_AGE:int = 19;
    var age:int;
 
    function IsTeen(): Boolean
    {
        return age &gt;= MIN_TEEN_AGE &amp;&amp; age &lt;= MAX_TEEN_AGE;
    }
}</pre><p></p>
<p>Вот, как это можно сделать в <strong>C#</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    private const int MinTeenAge = 13;
    private const int MaxTeenAge = 19;
    int Age;
 
    bool IsTeen()
    {
        return Age &gt;= MinTeenAge &amp;&amp; Age &lt;= MaxTeenAge;
    }
}</pre><p></p>
<p>Важный нюанс: в <strong>C#</strong> для констант можно использовать только базовые типы (например, <strong>int</strong>) и строки. Это необходимо потому, что подобное поле не будет существовать на самом деле, вместо этого, везде, где оно используется, будут подставлены значения этого поля. Так же, это означает, что подобные поля автоматически становятся статическими (<strong>static</strong>), и их не нужно объявлять, как <strong>static</strong> отдельно. После компиляции класс <strong>Person</strong> в <strong>C#</strong> будет выглядеть следующим образом:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    int Age;
 
    bool IsTeen()
    {
        return Age &gt;= 13 &amp;&amp; Age &lt;= 19;
    }
}</pre><p></p>
<p>В <strong>AS3</strong> ключевое слово <strong>const</strong> использовалось исключительно для проверки на этапе компиляции и не приводило к изменениям/подстановкам в коде. Если необходимо добиться похожего поведения в <strong>C#</strong> или необходимо использовать не базовый тип данных (например, <strong>Person</strong>), то нужно использовать ключевое слово <strong>readonly</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Person
{
    static readonly Person Newborn = new Person(0);
    readonly int Age;
 
    Person(int age)
    {
        Age = age;
    }
}</pre><p></p>
<p>В примере выше присутствует 2 <strong>readonly</strong> поля:</p>
<p>1) <strong>Newborn</strong> &#8211; поле, которое было объявлено с ключевым словом <strong>static</strong> (<strong>readonly</strong> поля, в отличии от констант, не обязательно являются <strong>static</strong>). Данное поле будет инициализировано в том месте, где оно объявлено (по-аналогии с константами в <strong>AS3</strong>).</p>
<p>2) <strong>Age</strong> &#8211; поле, которое является <strong>readonly</strong>, но не является <strong>static</strong>. Оно будет инициализировано в конструкторе.</p>
<p>&nbsp;</p>
<p>В завершении, сравнение описанных особенностей <strong>C#</strong> и <strong>AS3</strong> кода:</p>
<table>
<tbody>
<tr>
<td>
<pre class="crayon-plain-tag">////////
// C# //
////////
 
// Collection of classes being used by this file
using org.apache.coolstuff;
 
// Collection of classes
namespace com.jacksondunstan.examples
{
    class Person
    {
        // Complex getters and setters
        private String _name;
        String Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
 
        // Simple getters and setters
        int Age { get; set; }
 
        // Read-only field
        readonly int ID;
 
        // Inlined field
        const int AdultAge = 18;
 
        // Function that can't be overridden
        sealed void Print()
        {
            Debug.Log("Name: " + name + ", ID: " + ID);
        }
    }
}</pre>
</td>
<td>
<pre class="crayon-plain-tag">/////////
// AS3 //
/////////
 
// Collection of classes being used by this file
import org.apache.coolstuff;
 
// Collection of classes
package com.jacksondunstan.examples
{
    class Person
    {
        // Complex getters and setters
        private var _name:String;
        function get name(): String
        {
            return _name;
        }
        function set name(value:String): void
        {
            _name = value;
        }
 
 
 
 
        // Simple getters and setters
        // {not supported. use complex instead.}
 
        // Read-only field
        const var ID:int;
 
        // Inlined field
        // {not supported. use compile-time constants via command-line instead.}
 
        // Function that can't be overridden
        final function print(): void
        {
            trace("Name: " + name + ", ID: " + ID);
        }
    }
}</pre>
</td>
</tr>
</tbody>
</table>
<p>В следующей статье мы, наконец-то, начнём рассматривать понятия, аналогов которых нет в <strong>AS3</strong>.</p>
<p>Не переключайте канал!</p>
<p>&nbsp;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2015/01/26/c-sharp-for-as3-developers-part-3-get-set-sealed-using-const-readonly/">С# для AS3 разработчиков. Часть 3: get, set, sealed, using, const, readonly</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://flashist.ru/2015/01/26/c-sharp-for-as3-developers-part-3-get-set-sealed-using-const-readonly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>С# для AS3 разработчиков. Часть 2: Расширение классов и реализация Интерфейсов</title>
		<link>https://flashist.ru/2014/12/17/c-sharp-for-as3-developers-part-2-class-inheretance-and-interface-implementation/</link>
		<comments>https://flashist.ru/2014/12/17/c-sharp-for-as3-developers-part-2-class-inheretance-and-interface-implementation/#comments</comments>
		<pubDate>Wed, 17 Dec 2014 18:50:03 +0000</pubDate>
		<dc:creator><![CDATA[Flashist]]></dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# для AS3 разработчиков]]></category>
		<category><![CDATA[Gamedev]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://flashist.ru/?p=60</guid>
		<description><![CDATA[<p>Перевод статьи From AS3 to C#, Part 2: Extending Classes and Implementing Interfaces Эта статья продолжает серию &#8220;C# для&#8230;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2014/12/17/c-sharp-for-as3-developers-part-2-class-inheretance-and-interface-implementation/">С# для AS3 разработчиков. Часть 2: Расширение классов и реализация Интерфейсов</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p><a href="http://flashist.ru/wp-content/uploads/2014/12/PostImage_600x3001.png"><img class="alignnone wp-image-63 size-full" src="http://flashist.ru/wp-content/uploads/2014/12/PostImage_600x3001.png" alt="PostImage_600x300" width="600" height="300" /></a></p>
<p><em>Перевод статьи <a href="http://jacksondunstan.com/articles/2703">From AS3 to C#, Part 2: Extending Classes and Implementing Interfaces</a></em></p>
<p>Эта статья продолжает серию &#8220;<a href="http://flashist.ru/category/c-sharp-for-as3-developers/">C# для AS3 разработчиков</a>&#8220;, и сегодня мы рассмотрим устройство классов в <strong>C#</strong> с точки зрения <strong>AS3</strong> разработчика (наследование классов, реализация интерфейсов и наследование интерфейсов).</p>
<p><span id="more-60"></span><br />Начнём с наследования классов. Вот, как это выглядит в <strong>AS3</strong>:</p>
<p></p><pre class="crayon-plain-tag">class Shape
{
}
 
class Circle extends Shape
{
}</pre><p></p>
<p>А вот, как это выглядить в C#:</p>
<p></p><pre class="crayon-plain-tag">class Shape
{
}
 
class Circle : Shape
{
}</pre><p></p>
<p>Как вы могли заметить, вместо ключевого слова extends, используется : (двоеточие).</p>
<p>Похожим образом обстоят дела с реализацией интерфейсов. Как это выглядит в AS3:</p>
<p></p><pre class="crayon-plain-tag">interface IHasArea
{
    function GetArea(): int;
}
 
interface IRound
{
    function GetSmoothness(): int;
}
 
class Shape
{
}
 
class Circle extends Shape implements IHasArea, IRound
{
    function GetArea(): int
    {
        return 33; // TODO рассчитать
    }
 
    function GetSmoothness(): int
    {
        return 44; // TODO рассчитать
    }
}</pre><p></p>
<p>Та же самая структура кода, но в C#:</p>
<p></p><pre class="crayon-plain-tag">interface IHasArea
{
    int GetArea();
}
 
interface IRound
{
    int GetSmoothness();
}
 
class Shape
{
}
 
class Circle : Shape, IHasArea, IRound
{
    int GetArea()
    {
        return 33; // TODO рассчитать
    }
 
    int GetSmoothness()
    {
        return 44; // TODO рассчитать
    }
}</pre><p></p>
<p>В С#, двоеточие используется вместо ключевого слова implements, по такому же принципу, как и с extends. Описание интерфейсов в C# похоже на описание оных в AS3.</p>
<p>Пример расширения интерфейсов в AS3:</p>
<p></p><pre class="crayon-plain-tag">interface ISuper
{
}
 
interface ISub extends ISuper
{
}</pre><p></p>
<p>Скорее всего, вы уже догадываетесь, как этот код выглядит в C#&#8230;</p>
<p></p><pre class="crayon-plain-tag">interface ISuper
{
}
 
interface ISub : ISuper
{
}</pre><p></p>
<p>Давайте разберёмся, как описываются отношения между родительскими и дочерними классами/интерфейсами в C#. В AS3 вы можете использовать ключевые слова this и super в любых не статических функциях, чтобы обратиться к экземпляру текущего класса (this) или к экземпляру родительского класса (super). Например:</p>
<p></p><pre class="crayon-plain-tag">class Polygon
{
    var numVertices:uint;
 
    function printDescription(): String
    {
        return "Polygon (numVertices=" + numVertices + ")";
    }
}
 
class Triangle extends Polygon
{
    var color:String;
    var polygonDescriptionAtConstructionTime:String;
 
    function Triangle(color:String)
    {
        this.color = color;
        polygonDescriptionAtConstructionTime = super.printDescription();
    }
 
    function printDescription(): String
    {
        return "Triangle (color=" + color + ")";
    }
}</pre><p></p>
<p>В данном примере, ключевое слово super обращается исключительно к переменным и функциям класса Polygon. Такой способ обращения к функциям используется крайне редко, но иногда он может помочь избежать в коде двусмысленностей, относительно того, какая из функций printDescription будет вызвана. Если бы в данном примере не использовалось слово super, то вызывалась бы функция printDescription класса Triangle, т.к. поиск в текущем классе происходит раньше родительского класса.</p>
<p>Ключевое слово this обращается исключительно к переменным и функциям класса Triangle. В примере, this используется, чтобы компилятор понимал, что нужно обрщаться к переменной color класса Triangle, а не к одноимённой переменной, передаваемой в конструктор.</p>
<p>А теперь версия на C#:</p>
<p></p><pre class="crayon-plain-tag">class Polygon
{
    uint NumVertices;
 
    String PrintDescription()
    {
        return "Polygon (numVertices=" + numVertices + ")";
    }
}
 
class Triangle : Polygon
{
    String Color;
    String PolygonDescriptionAtConstructionTime;
 
    Triangle(String color)
    {
        this.Color = color;
        PolygonDescriptionAtConstructionTime = base.printDescription();
    }
 
    String printDescription()
    {
        return "Triangle (color=" + color + ")";
    }
}</pre><p></p>
<p>Эти два примера очень похожи, за исключением того, что в C#, вместо ключевого слова super, используется ключевое слово base. В C# base выполняет те же функции, что и super в AS3.</p>
<p>Другой пример использования super в AS3 (вызов родительского конструктора):</p>
<p></p><pre class="crayon-plain-tag">class Polygon
{
    var numVertices:uint;
 
    function Polygon(numVertices:uint)
    {
        this.numVertices = numVertices;
    }
}
 
class Triangle extends Polygon
{
    var color:String;
 
    function Triangle(numVertices:uint, color:String)
    {
        super(numVertices);
        this.color = color;
    }
}</pre><p></p>
<p>C# версия:</p>
<p></p><pre class="crayon-plain-tag">class Polygon
{
    uint NumVertices;
 
    Polygon(uint numVertices)
    {
        NumVertices = numVertices;
    }
}
 
class Triangle : Polygon
{
    String Color;
 
    Triangle(uint numVertices, String color)
        : base(numVertices)
    {
    }
}</pre><p></p>
<p>Помимо того, что мы снова заменили super на base, вы можете заметить, что вызов происходит до выполнения кода в конструкторе (до фигурных скобок {}). Так же, вызову конструктора родительского класса предшествует двоеточие (:). Обратите внимание, что в конце строки вызова, не ставится точка с запятой (;).</p>
<p>Давайте разберём, как в AS3 сделать так, чтобы класс нельзя было расширить:</p>
<p></p><pre class="crayon-plain-tag">final class FinalClass
{
}
 
// Этот класс не будет компилироваться
class DerviedClass extends FinalClass
{
}</pre><p></p>
<p>Похожий функционал в C#:</p>
<p></p><pre class="crayon-plain-tag">sealed class FinalClass
{
}
 
// Этот класс не будет компилироваться
class DerviedClass : FinalClass
{
}</pre><p></p>
<p>В данном случае различия между C# и AS3 состоят только в названии ключевых слов. В C# класс, котоырй нельзя расширить обозначается ключевым словом sealed, а в AS3 для этого используется final, но эффект &#8211; абсолютно одинаковый.</p>
<p>В завершении, сравнение описанных особенностей C# и AS3 кода:</p>
<table>
<tbody>
<tr>
<td>
<pre class="crayon-plain-tag">////////
// C# //
////////
 
// Interface
interface IShape
{
    String GetDescription();
}
 
// Sub-interface (one that extends another)
interface IPolygon : IShape
{
    uint GetNumEdges();
}
 
// Class
class Shape
{
    String Name;
 
    Shape(String name)
    {
        Name = name;
    }
}
 
// Derived class (one that extends another)
class Circle : Shape
{
    int Radius;
 
    Circle(String name, int radius)
        : base(name)
    {
        Radius = radius;
    }
}
 
// Derived class that also implements an interface
class Triangle : Shape, IPolygon
{
    Triangle()
        : base("Triangle")
    {
    }
 
    uint GetNumEdges()
    {
        return 3;
    }
 
    String GetDescription()
    {
        return "A three-sided polygon";
    }
}
 
// Class that can't be extended
sealed class NoDerivatives
{
}</pre>
</td>
<td>
<pre class="crayon-plain-tag">/////////
// AS3 //
/////////
 
// Interface
interface IShape
{
    function getDescription(): String;
}
 
// Sub-interface (one that extends another)
interface IPolygon extends IShape
{
    function getNumEdges(): uint;
}
 
// Class
class Shape
{
    var name:String;
 
    function Shape(name:String)
    {
        this.name = name;
    }
}
 
// Derived class (one that extends another)
class Circle extends Shape
{
    var Radius:int;
 
    function Circle(name:String, radius:int)
    {
        super(name);
        Radius = radius;
    }
}
 
// Derived class that also implements an interface
class Triangle extends Shape implements IPolygon
{
    function Triangle()
    {
        super("Triangle");
    }
 
    function GetNumEdges(): uint
    {
        return 3;
    }
 
    function GetDescription(): String
    {
        return "A three-sided polygon";
    }
}
 
// Class that can't be extended
final class NoDerivatives
{
}</pre>
</td>
</tr>
</tbody>
</table>
<p>На этом мы сегодня закругляемся. В следующей статье мы поговорим о геттерах и сеттерах (<strong>getter</strong>/<strong>setter</strong>) и закончим описание основ классов. После чего, мы сможем перейти к нюансам <strong>C#</strong>, аналогов которых нет в <strong>AS3</strong>.</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2014/12/17/c-sharp-for-as3-developers-part-2-class-inheretance-and-interface-implementation/">С# для AS3 разработчиков. Часть 2: Расширение классов и реализация Интерфейсов</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://flashist.ru/2014/12/17/c-sharp-for-as3-developers-part-2-class-inheretance-and-interface-implementation/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>С# для AS3 разработчиков. Часть 1: Основы классов</title>
		<link>https://flashist.ru/2014/12/15/c-sharp-for-as3-developers-part-1-class-basics/</link>
		<comments>https://flashist.ru/2014/12/15/c-sharp-for-as3-developers-part-1-class-basics/#comments</comments>
		<pubDate>Mon, 15 Dec 2014 17:13:29 +0000</pubDate>
		<dc:creator><![CDATA[Flashist]]></dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# для AS3 разработчиков]]></category>
		<category><![CDATA[Gamedev]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://flashist.ru/?p=18</guid>
		<description><![CDATA[<p>  Перевод статьи From AS3 to C#, Part 1: Class Basics Эта статья поможет разобраться в основах C# тем&#8230;</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2014/12/15/c-sharp-for-as3-developers-part-1-class-basics/">С# для AS3 разработчиков. Часть 1: Основы классов</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>  <a href="http://flashist.ru/wp-content/uploads/2014/12/PostImage_600x300.png"><img class="alignnone wp-image-56 size-full" src="http://flashist.ru/wp-content/uploads/2014/12/PostImage_600x300.png" alt="PostImage_600x300" width="600" height="300" /></a></p>
<p><em>Перевод статьи <a href="http://jacksondunstan.com/articles/2634">From AS3 to C#, Part 1: Class Basics</a></em></p>
<p>Эта статья поможет разобраться в основах <a href="http://flashist.ru/category/c-sharp-for-as3-developers/"><strong>C#</strong> тем <strong>AS3</strong> разработчикам</a>, которые решили переключиться на <strong>Unity</strong>, но абсолютно не знакомы с программированием на <strong>C#</strong>.</p>
<p><span id="more-18"></span><br /> Начнём с главного: С# файлы имеют расширение <strong>.cs</strong>, а не <strong>.as</strong> как AS3 файлы. Внутри файлов вы найдёте описание классов, из которых состоят приложения (аналогично AS3 файлам). Например, файл <strong>MyClass.cs</strong>:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
}</pre><p></p>
<p>Название классов в C# подчиняется той же конвенции, что и названия классов в AS3: каждое слово в названии класса должно начинаться с большой буквы, остальная часть названия пишется в нижнем регистре. Как вы могли заметить, базовый синтаксис классов в C# такой же, как у классов в AS3.</p>
<p>Теперь давайте добавим переменную:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	int X;
}</pre><p></p>
<p>Определение переменных в C# отличается от AS3. Вместо <strong>var x:int</strong>, нужно использовать <strong>int X</strong>. Конвенция названий говорит, что названия переменных должны начинаться с большой буквы.</p>
<p>Давайте посмотрим на функции:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo()
	{
	}
}</pre><p></p>
<p>Функции в C# так же отличаются от функций в AS3. В C# не используется ключевое слово <strong>function</strong>, возвращаемый тип данный указывается вначале (а не в конце, как это было в AS3), название функций должно начинаться с большой буквы, исходя из конвенции названий.</p>
<p>Функция с входящими параметрами:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo(int x, int y, int z)
	{
	}
}</pre><p></p>
<p>Параметры функций, так же, как и в AS3, находятся внутри скобок, но записываются они немного по-другому: вначале тип, потом имя, с пробелом между ними. Конвенция говорит, что названия параметров функций должны начинаться с маленькой буквы.</p>
<p>Как и в AS3, параметры функций могут иметь значения по-умолчанию:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo(int x = 1, int y = 2, int z = 3)
	{
	}
}</pre><p></p>
<p>Функция-конструктор:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	MyClass()
	{
	}
}</pre><p></p>
<p>Как и в AS3, нам не обязательно указывать тип возвращаемого значения для функций-конструкторов. Вообще-то, у вас не получится указать даже тип данных <strong>void</strong>, как это можно было сделать в AS3. Так же, для объявления этого типа функций, не используется ключевое слово <strong>function</strong>.</p>
<p>Вы можете иметь больше одной функции-конструктора, это называется &#8220;перегрузка&#8221; функций:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	MyClass()
	{
	}
 
	MyClass(int x)
	{
	}
 
	MyClass(int x, int y, int z)
	{
	}
}</pre><p></p>
<p>Перезагрузка так же доступна для других функций:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo()
	{
	}
 
	void Foo(int x)
	{
	}
 
	void Foo(int x, int y, int z)
	{
	}
}</pre><p></p>
<p>Чтобы компилятор мог определить, какая из функций вызывается, необходимо придерживаться 2 правил. Во-первых, вы не можете иметь 2 функции с одинаковыми параметрами:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo(int x, int y, int z)
	{
		// Какой-то функционал
	}
 
	void Foo(int x, int y, int z)
	{
		// Какой-то другой функционал
	}
}</pre><p></p>
<p>Это же касается тех функций, вызов которых может выглядеть одинаково, если не будет указан один из параметров по-умолчанию:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	void Foo(int x, int y, int z)
	{
		// Какой-то функционал
	}
 
	void Foo(int x, int y, int z, int w = 0)
	{
		// Какой-то другой функционал
	}
}</pre><p></p>
<p>Во-вторых, вы не можете &#8220;перегружать&#8221; функции по типу данных, который они возвращают:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	int Foo(int x, int y, int z)
	{
		return 0;
	}
 
	uint Foo(int x, int y, int z)
	{
		return 0;
	}
}</pre><p></p>
<p>Придерживаясь этих двух простых правил, вы сможете &#8220;перегружать&#8221; функции, сколько ваша душа пожелает =)</p>
<p>Как и в AS3, для определения статических функций необходимо добавить ключевое слово <strong>static</strong>:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	static void Foo()
	{
	}
}</pre><p></p>
<p>То же самое со статическими переменными:</p>
<p></p><pre class="crayon-plain-tag">class MyClass
{
	static int X;
}</pre><p></p>
<p>Теперь, когда мы знаем, как внутри классов определять классы, переменные, функции и конструкторы, давайте рассмотрим как использовать их:</p>
<p></p><pre class="crayon-plain-tag">void SomeCode()
{
	// Вызов конструктора по-умолчанию (например, без входящих параметров)
	MyClass mc = new MyClass()
 
	// Вызов другого конструктора
	mc = new MyClass(5);
 
	// Вызов функции
	mc.Foo();
 
	// Вызов перегруженной функции
	mc.Foo(1, 2, 3);
 
	// Вызов статической функции
	MyClass.Foo();
 
	// Получение значения переменной
	mc.X;
 
	// Установка значения переменной
	mc.X = 1;
 
	// By the way, single-line comments are the same...
	// Кстати, однострочные комментарии работают так же, как и в AS3...
 
	/*
	... многострочные комментарие тоже.
	*/
}</pre><p></p>
<p>Всё это очень похоже на AS3. Обратите внимание, что локальная переменная mc начинается с маленькой буквы, как и параметры функций.</p>
<p>Давайте обсудим модификаторы доступа. Стандартные модификаторы <strong>public</strong>, <strong>private</strong> и <strong>protected</strong> имеют такой же синтаксис и такое же поведение, как и в AS3. Для их использования достаточно просто добавить их перед возвращаемым типом данных функции, типом переменной или ключевым словом <strong>class</strong>:</p>
<p></p><pre class="crayon-plain-tag">public class MyClass
{
	private int X;
 
	protected void Foo()
	{
	}
}</pre><p></p>
<p>В C#, как и в AS3, существует модификатор доступа <strong>internal</strong>, который имеет такое же название, но немного другое поведение (по-сравнению с AS3). В AS3 модификатор <strong>internal</strong> означает &#8220;доступно для текущего класса и других классов в текущем пакете&#8221;. В C# он означает &#8220;доступно для текущего класса и остальных классов в текущей сборке&#8221;. Я расскажу про понятие &#8220;сборки&#8221; в других статьях, но пока что, думайте о них, как о группе классов, собранных в одном бинарном файле.</p>
<p>Так же, в C# есть модификатор <strong>protected internal</strong>, который является комбинацией <strong>protected</strong> и <strong>internal</strong>.</p>
<p>В завершении, сравнение описанных особенностей C# и AS3 кода:</p>
<table>
<tbody>
<tr>
<td>
<pre class="crayon-plain-tag">////////
// C# //
////////
 
/////////////////
// Declaration //
/////////////////
 
// Class
public class MyClass
{
	// Field variable
	public int X;
 
	// Class variable
	static public int Y;
 
	// Default constructor
	public MyClass()
	{
	}
 
	// Overloaded constructor
	public MyClass(int x)
	{
	}
 
	// Instance function
	public void Foo()
	{
	}
 
	// Overloaded instance function
	public void Foo(int x)
	{
	}
 
	// Class function
	static public void Goo()
	{
	}
 
	// Overloaded class function
	static public void Goo(int x)
	{
	}
}
 
///////////
// Usage //
///////////
 
// Call the default constructor
MyClass mc = new MyClass()
 
// Call a different constructor
mc = new MyClass(5);
 
// Call an instance function
mc.Foo();
 
// Call an overloaded instance function
mc.Foo(1);
 
// Call a static function
MyClass.Goo();
 
// Call an overloaded static function
MyClass.Goo(1);
 
// Get an instance variable
mc.X;
 
// Set an instance variable
mc.X = 1;
 
// Get a class variable
MyClass.Y;
 
// Set a class variable
MyClass.Y = 1;
 
// Single-line comment
 
/*
Multi-line comment
*/</pre>
</td>
<td>
<pre class="crayon-plain-tag">/////////
// AS3 //
/////////
 
/////////////////
// Declaration //
/////////////////
 
// Class
public class MyClass
{
	// Field variable
	public var x:int;
 
	// Class variable
	static public var y:int;
 
	// Default constructor
	public function MyClass()
	{
	}
 
	// Overloaded constructor
	// {not supported}
 
 
 
	// Instance function
	public function foo(): void
	{
	}
 
	// Overloaded instance function
	// {not supported}
 
 
 
	// Class function
	static public function goo(): void
	{
	}
 
	// Overloaded class function
	// {not supported}
 
 
}
 
///////////
// Usage //
///////////
 
// Call the default constructor
var mc:MyClass = new MyClass()
 
// Call a different constructor
mc = new MyClass(5);
 
// Call an instance function
mc.foo();
 
// Call an overloaded instance function
// {not supported}
 
// Call a static function
MyClass.goo();
 
// Call an overloaded static function
// {not supported}
 
// Get an instance variable
mc.x;
 
// Set an instance variable
mc.x = 1;
 
// Get a class variable
MyClass.y;
 
// Set a class variable
MyClass.y = 1;
 
// Single-line comment
 
/*
Multi-line comment
*/</pre>
</td>
</tr>
</tbody>
</table>
<p>Этим завершается первая часть цикла статей &#8220;<a href="http://flashist.ru/category/c-sharp-for-as3-developers/">С# для AS3 разработчиков</a>&#8220;. Следующие статьи будут касаться более сложных тем, включая такие особенности C#, аналоги которых не существуют в AS3.</p>
<p>Оставайтесь на связи!</p>
<p>Запись <a rel="nofollow" href="https://flashist.ru/2014/12/15/c-sharp-for-as3-developers-part-1-class-basics/">С# для AS3 разработчиков. Часть 1: Основы классов</a> впервые появилась <a rel="nofollow" href="https://flashist.ru">Flashist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://flashist.ru/2014/12/15/c-sharp-for-as3-developers-part-1-class-basics/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
