Xamarin для разработчиков JavaXamarin for Java Developers

Если вы разработчик Java, вы можете применять свои навыки работы с существующим кодом на платформе Xamarin, получая возможность повторно использовать код C#. Вы заметите, что синтаксис C# очень напоминает синтаксис Java и что оба языка обеспечивают очень схожие функции. Кроме того, вы ознакомитесь с уникальными функциями C#, которые упрощают разработку.If you are a Java developer, you are well on your way to leveraging your skills and existing code on the Xamarin platform while reaping the code reuse benefits of C#. You will find that C# syntax is very similar to Java syntax, and that both languages provide very similar features. In addition, you'll discover features unique to C# that will make your development life easier.

ОбзорOverview

Из этой статьи вы узнаете о программировании C# для разработчиков Java, а также ознакомитесь с функциями языка C#, которые используются при разработке приложений Xamarin.Android.This article provides an introduction to C# programming for Java developers, focusing primarily on the C# language features that you will encounter while developing Xamarin.Android applications. Здесь также объясняется, как эти функции отличаются от таких же функций Java. Здесь описываются важные функции C# (применимые к Xamarin.Android), недоступные в Java.Also, this article explains how these features differ from their Java counterparts, and it introduces important C# features (relevant to Xamarin.Android) that are not available in Java. В этом руководстве содержатся ссылки на дополнительные справочные материалы, поэтому его можно использовать как стартовую точку для дальнейшего изучения C# и .NET.Links to additional reference material are included, so you can use this article as a "jumping off" point for further study of C# and .NET.

Если вы знакомы с Java, понимание синтаксиса C# не вызовет никаких сложностей.If you are familiar with Java, you will feel instantly at home with the syntax of C#. Синтаксис C# очень похож на синтаксис Java — в C#, как и в Java, C и C++, используются фигурные скобки.C# syntax is very similar to Java syntax – C# is a "curly brace" language like Java, C, and C++. Во многих отношениях синтаксис C# считается расширенным вариантом синтаксиса Java, но с несколькими переименованными и добавленными ключевыми словами.In many ways, C# syntax reads like a superset of Java syntax, but with a few renamed and added keywords.

В C# можно найти многие основные характеристики Java:Many key characteristics of Java can be found in C#:

  • основанное на классах объектно-ориентированное программирование;Class-based object-oriented programming

  • строгая типизация;Strong typing

  • поддержка интерфейсов;Support for interfaces

  • Универсальные шаблоныGenerics

  • Сборка мусораGarbage collection

  • компиляция среды выполнения.Runtime compilation

Java и C# компилируются в промежуточный язык, выполняемый в управляемой среде выполнения.Both Java and C# are compiled to an intermediate language that is run in a managed execution environment. C# и Java являются статически типизированными и распознают строки как неизменяемые типы.Both C# and Java are statically-typed, and both languages treat strings as immutable types. Оба языка используют иерархию классов с одним корнем.Both languages use a single-rooted class hierarchy. Подобно Java, C# поддерживает только одно наследование и не позволяет использовать глобальные методы.Like Java, C# supports only single inheritance and does not allow for global methods. В этих языках объекты создаются в куче с использованием ключевого слова new и удаляются сборщиком мусора, когда в них больше нет необходимости.In both languages, objects are created on the heap using the new keyword, and objects are garbage-collected when they are no longer used. Оба языка обеспечивают официальную поддержку обработки исключений с помощью семантики try/catch,Both languages provide formal exception handling support with try/catch semantics. а также поддержку синхронизации и управления потоками.Both provide thread management and synchronization support.

Однако между этими языками есть немало различий.However, there are many differences between Java and C#. Например:For example:

  • Java не поддерживает неявно типизированные локальные переменные (C# поддерживает ключевое слово var).Java does not support implicitly-typed local variables (C# supports the var keyword).

  • В Java вы можете передавать параметры только по значению, тогда как в C# их можно передавать как по ссылке, так и по значению.In Java, you can pass parameters only by value, while in C# you can pass by reference as well as by value. (C# предоставляет ключевые слова ref и out для передачи параметров по ссылке. В Java нет эквивалентов.)(C# provides the ref and out keywords for passing parameters by reference; there is no equivalent to these in Java).

  • Java не поддерживает директивы препроцессора, например #define.Java does not support preprocessor directives like #define.

  • Java не поддерживает целочисленные типы без знака, а в C# такие типы есть, например ulong, uint, ushort и byte.Java does not support unsigned integer types, while C# provides unsigned integer types such as ulong, uint, ushort and byte.

  • Java не поддерживает перегрузку операторов. В C# вы можете перегружать операторы и преобразования.Java does not support operator overloading; in C# you can overload operators and conversions.

  • В инструкции switch Java код может попасть в следующий раздел switch, но в C# в конце каждого раздела switch должен находиться переключатель (каждый раздел должен закрываться с помощью инструкции break).In a Java switch statement, code can fall through into the next switch section, but in C# the end of every switch section must terminate the switch (the end of each section must close with a break statement).

  • В Java вы указываете исключения, создаваемые методом с ключевым словом throws, но в C# нет понятия проверенных исключений — ключевое слово throws не поддерживается в C#.In Java, you specify the exceptions thrown by a method with the throws keyword, but C# has no concept of checked exceptions – the throws keyword is not supported in C#.

  • C# поддерживает синтаксис LINQ, который позволяет использовать зарезервированные слова from, select и where для написания запросов к коллекциям способом, похожим на запросы к базе данных.C# supports Language-Integrated Query (LINQ), which lets you use the reserved words from, select, and where to write queries against collections in a way that is similar to database queries.

Разумеется, между C# и Java имеется гораздо больше различий, которые никак нельзя рассмотреть в одной статье.Of course, there are many more differences between C# and Java than can be covered in this article. Кроме того, Java и C# продолжают развиваться (например, Java 8 — версия, которой еще нет в цепочке инструментов Android, поддерживает лямбда-выражения в стиле C#), поэтому эти различия со временем будут изменяться.Also, both Java and C# continue to evolve (for example, Java 8, which is not yet in the Android toolchain, supports C#-style lambda expressions) so these differences will change over time. Здесь перечислены только самые важные отличия, с которыми в настоящее время сталкиваются разработчики Java, только начинающие изучать расширение Xamarin.Android.Only the most important differences currently encountered by Java developers new to Xamarin.Android are outlined here.

C# предоставляет ряд основных функций Xamarin.Android, которые в настоящее время не доступны для разработчиков Java на Android.C# brings many key features to Xamarin.Android that are not currently readily available to Java developers on Android. С помощью этих функций можно написать качественный код за короткий срок.These features can help you to write better code in less time:

  • Свойства — с помощью системы свойств C# можно напрямую и безопасно получить доступ к переменным-элементам без необходимости писать методы задания и получения.Properties – With C#'s property system, you can access member variables safely and directly without having to write setter and getter methods.

  • Лямбда-выражения – C# позволяет использовать анонимные методы (также называемые лямбда-выражениями) для более эффективного и лаконичного выражения функций.Lambda Expressions – In C# you can use anonymous methods (also called lambdas) to express your functionality more succinctly and more efficiently. Вы можете избежать сложностей, связанных с необходимостью писать одноразовые объекты, и передать локальное состояние методу без необходимости добавлять параметры.You can avoid the overhead of having to write one-time-use objects, and you can pass local state to a method without having to add parameters.

  • Обработка событий — C# обеспечивает поддержку на уровне языка для программирования на основе событий, где объект можно зарегистрировать для получения уведомления о соответствующем событии.Event Handling – C# provides language-level support for event-driven programming, where an object can register to be notified when an event of interest occurs. Ключевое слово event определяет механизм многоадресного вещания, который класс издателя может использовать для уведомления подписчиков событий.The event keyword defines a multicast broadcast mechanism that a publisher class can use to notify event subscribers.

  • Асинхронное программирование — функции асинхронного программирования C# (async/await) обеспечивают быстрое реагирование приложений.Asynchronous Programming – The asynchronous programming features of C# (async/await) keep apps responsive. Поддержка этой функции на уровне языка упрощает реализацию асинхронного программирования и снижает вероятность ошибок.The language-level support of this feature makes async programming easy to implement and less error-prone.

И, наконец, Xamarin позволяет использовать имеющиеся ресурсы Java с помощью технологии привязки.Finally, Xamarin allows you to leverage existing Java assets via a technology known as binding. Вы можете вызвать имеющийся Java-код, платформы и библиотеки из C# с помощью автоматических генераторов привязки Xamarin.You can call your existing Java code, frameworks, and libraries from C# by making use of Xamarin's automatic binding generators. Для этого нужно просто создать статическую библиотеку в Java и предоставить ее C# через привязку.To do this, you simply create a static library in Java and expose it to C# via a binding.

Переход от разработки на Java к разработке на C#Going From Java to C# Development

В следующих разделах описываются основные базовые различия между C# и Java. В разделе ближе к концу статьи описываются объектно-ориентированные различия между этими языками.The following sections outline the basic "getting started" differences between C# and Java; a later section describes the object-oriented differences between these languages.

Библиотеки и СборкиLibraries vs. Assemblies

Java обычно упаковывает связанные классы в JAR-файлы.Java typically packages related classes in .jar files. Однако в C# и .NET предварительно скомпилированный код, который можно многократно использовать, упаковывается в сборки, которые обычно объединяются в пакет как DLL-файлы.In C# and .NET, however, reusable bits of precompiled code are packaged into assemblies, which are typically packaged as .dll files. Сборка — это единица развертывания кода C# или .NET. Каждая сборка обычно связана с проектом C#.An assembly is a unit of deployment for C#/.NET code, and each assembly is typically associated with a C# project. Сборки содержат промежуточный код, который компилируется в среде выполнения по методу JIT.Assemblies contain intermediate code (IL) that is just-in-time compiled at runtime.

Дополнительные сведения о сборках см. в разделе Сборки и глобальный кэш сборок.For more information about assemblies, see the Assemblies and the Global Assembly Cache topic.

Пакеты и Пространства именPackages vs. Namespaces

C# использует ключевое слово namespace, чтобы сгруппировать связанные типы. В Java эквивалентом является ключевое слово package.C# uses the namespace keyword to group related types together; this is similar to Java's package keyword. Обычно приложение Xamarin.Android размещается в пространстве имен, созданном для него.Typically, a Xamarin.Android app will reside in a namespace created for that app. Например, следующий код C# объявляет программу-оболочку пространства имен WeatherApp для приложения отправки отчетов о погоде:For example, the following C# code declares the WeatherApp namespace wrapper for a weather-reporting app:

namespace WeatherApp
{
    ...

Импорт типовImporting Types

Когда вы используете типы, определенные во внешних пространствах имен, вы импортируете их с помощью инструкции using (которая очень похожа на инструкцию import Java).When you make use of types defined in external namespaces, you import these types with a using statement (which is very similar to the Java import statement). В Java вы можете импортировать один тип с инструкцией, подобной следующей:In Java, you might import a single type with a statement like the following:

import javax.swing.JButton

Вы можете импортировать весь пакет Java с помощью инструкции, подобной ниже:You might import an entire Java package with a statement like this:

import javax.swing.*

Инструкция using C# работает очень схожим образом, но она позволяет вам импортировать весь пакет без указания подстановочного знака.The C# using statement works in a very similar way, but it allows you to import an entire package without specifying a wildcard. Например, вы будете часто встречать серию инструкций using в начале исходных файлов Xamarin.Android, как показано в этом примере:For example, you will often see a series of using statements at the beginning of Xamarin.Android source files, as seen in this example:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Net;
using System.IO;
using System.Json;
using System.Threading.Tasks;

С помощью этих инструкций импортируются функции из System, Android.App, Android.Content и других пространств имен.These statements import functionality from the System, Android.App, Android.Content, etc. namespaces.

Универсальные шаблоныGenerics

Java и C# поддерживают универсальные шаблоны, которые являются заполнителями, позволяющими подключаться к различным типам во время компиляции.Both Java and C# support generics, which are placeholders that let you plug in different types at compile time. Однако в C# универсальные шаблоны работают несколько иначе.However, generics work slightly differently in C#. В Java при использовании стирания типа сведения становятся доступными только во время компиляции, а не выполнения.In Java, type erasure makes type information available only at compile time, but not at run time. И напротив, среда выполнения CLR .NET обеспечивает явную поддержку универсальных типов. Это означает, что в этой среде у C# есть доступ к сведениям о типах.By contrast, the .NET common language runtime (CLR) provides explicit support for generic types, which means that C# has access to type information at runtime. В повседневной разработке Xamarin.Android важность этого различия не всегда очевидна, но если вы используете отражение, именно эта функция будет определять доступ к сведениям о типах во время выполнения.In day-to-day Xamarin.Android development, the importance of this distinction is not often apparent, but if you are using reflection, you will depend on this feature to access type information at run time.

В Xamarin.Android вы будете часто видеть универсальный метод FindViewById, используемый для получения ссылки на элемент управления макета.In Xamarin.Android, you will often see the generic method FindViewById used to get a reference to a layout control. Этот метод принимает параметр универсального типа, который определяет тип элемента управления для поиска.This method accepts a generic type parameter that specifies the type of control to look up. Например:For example:

TextView label = FindViewById<TextView> (Resource.Id.Label);

В этом примере кода метод FindViewById получает ссылку на элемент управления TextView, который определен в макете как метка, а затем возвращает его как тип TextView.In this code example, FindViewById gets a reference to the TextView control that is defined in the layout as Label, then returns it as a TextView type.

Дополнительные сведения об универсальных шаблонах см. в статье Универсальные шаблоны.For more information about generics, see the Generics topic. Обратите внимание, что в поддержке Xamarin.Android есть некоторые ограничения для универсальных классов C#. Дополнительные сведения см. в этом разделе.Note that there are some limitations in Xamarin.Android support for generic C# classes; for more information, see Limitations.

Функции объектно-ориентированного программированияObject-Oriented Programming Features

Java и C# используют очень похожие способы объектно-ориентированного программирования.Both Java and C# use very similar object-oriented programming idioms:

  • Все классы в конечном итоге выводятся из одного корневого объекта: все объекты Java выводятся из java.lang.Object, а все объекты C# — из System.Object.All classes are ultimately derived from a single root object – all Java objects derive from java.lang.Object, while all C# objects derive from System.Object.

  • Экземпляры классов являются ссылочными типами.Instances of classes are reference types.

  • Когда вы обращаетесь к свойствам и методам экземпляра, вы используете оператор ..When you access the properties and methods of an instance, you use the "." operator.

  • Все экземпляры классов создаются в куче через оператор new.All class instances are created on the heap via the new operator.

  • Так как оба языка используют сборку мусора, явно освободить неиспользуемые объекты невозможно (т. е. в этих языках нет ключевого слова delete, как в C++).Because both languages use garbage collection, there is no way to explicitly release unused objects (i.e., there is not a delete keyword as there is in C++).

  • Вы можете расширять классы через наследование, и оба языка допускают только один базовый класс для каждого типа.You can extend classes through inheritance, and both languages only allow a single base class per type.

  • Вы можете определить интерфейсы, а класс может наследовать (например, реализовывать) функции из нескольких определений интерфейсов.You can define interfaces, and a class can inherit from (i.e., implement) multiple interface definitions.

Однако есть и некоторые важные отличия.However, there are also some important differences:

  • Java поддерживает две эффективные функции, которые не поддерживаются в C#: анонимные классы и внутренние.Java has two powerful features that C# does not support: anonymous classes and inner classes. (Тем не менее, C# разрешает вложение определений классов: вложенные классы C# аналогичны статическим вложенным классам Java.)(However, C# does allow nesting of class definitions – C#'s nested classes are like Java's static nested classes.)

  • C# в отличие от Java поддерживает типы структуры стиля C (struct).C# supports C-style structure types (struct) while Java does not.

  • В C# вы можете реализовать определение класса в отдельных исходных файлах с использованием ключевого слова partial.In C#, you can implement a class definition in separate source files by using the partial keyword.

  • Интерфейсы C# не могут объявлять поля.C# interfaces cannot declare fields.

  • C# использует синтаксис деструктора стиля C++ для выражения методов завершения.C# uses C++-style destructor syntax to express finalizers. Синтаксис отличается от метода finalize Java, но семантика почти одинакова.The syntax is different from Java's finalize method, but the semantics are nearly the same. (Обратите внимание, что в C# деструкторы автоматически вызывают деструктор базового класса, в отличие от Java, где используется явный вызов super.finalize.)(Note that in C#, destructors automatically call the base-class destructor – in contrast to Java where an explicit call to super.finalize is used.)

Наследование классовClass Inheritance

Чтобы расширить класс в Java, нужно использовать ключевое слово extends.To extend a class in Java, you use the extends keyword. Чтобы расширить класс в C#, нужно использовать двоеточие (:) для указания наследования.To extend a class in C#, you use a colon (:) to indicate derivation. Например, в приложениях Xamarin.Android вы будете часто встречать наследования классов, которые напоминают фрагмент кода ниже:For example, in Xamarin.Android apps, you will often see class derivations that resemble the following code fragment:

public class MainActivity : Activity
{
    ...

В этом примере MainActivity наследуется от класса Activity.In this example, MainActivity inherits from the Activity class.

Чтобы объявить поддержку интерфейса в Java, нужно использовать ключевое слово implements.To declare support for an interface in Java, you use the implements keyword. Однако в C# нужно просто добавить имена интерфейсов в список классов, которые будут использоваться для наследования, как показано в этом фрагменте кода:However, in C#, you simply add interface names to the list of classes to inherit from, as shown in this code fragment:

public class SensorsActivity : Activity, ISensorEventListener
{
    ...

В этом примере SensorsActivity наследуется от Activity и реализует функцию, объявленную в интерфейсе ISensorEventListener.In this example, SensorsActivity inherits from Activity and implements the functionality declared in the ISensorEventListener interface. Обратите внимание, что список интерфейсов должен следовать за базовым классом (в противном случае вы получите ошибку времени компиляции).Note that the list of interfaces must come after the base class (or you will get a compile-time error). По соглашению к именам интерфейсов C# добавляется "I" в верхнем регистре, что позволяет определить без ключевого слова implements, какие классы являются интерфейсами.By convention, C# interface names are prepended with an upper-case "I"; this makes it possible to determine which classes are interfaces without requiring an implements keyword.

Если вы не хотите, чтобы в C# к классу позднее было применено наследование, имени класса должно предшествовать ключевое слово sealed — в Java перед именем класса нужно использовать ключевое слово final.When you want to prevent a class from being further subclassed in C#, you precede the class name with sealed – in Java, you precede the class name with final.

Дополнительные сведения об определениях классов C# см. в разделах Классы и Наследование.For more about C# class definitions, see the Classes and Inheritance topics.

СвойстваProperties

В Java методы-мутаторы (методы задания) и методы-инспекторы (методы получения) часто используются для управления способами применения изменений к элементам класса со скрытием и защитой этих элементов от внешнего кода.In Java, mutator methods (setters) and inspector methods (getters) are often used to control how changes are made to class members while hiding and protecting these members from outside code. Например, класс TextView Android предоставляет методы getText и setText.For example, the Android TextView class provides getText and setText methods. C# обеспечивает аналогичный, но более прямой механизм, известный как свойства.C# provides a similar but more direct mechanism known as properties. Пользователи класса C# могут получить доступ к свойству так же, как они получают доступ к полю, но каждый доступ фактически приводит к вызову метода, который является прозрачным для вызывающего.Users of a C# class can access a property in the same way as they would access a field, but each access actually results in a method call that is transparent to the caller. Этот "неявный" метод может включать побочные эффекты, например установку других значений, выполнение преобразований или изменение состояния объекта.This "under the covers" method can implement side effects such as setting other values, performing conversions, or changing object state.

Свойства часто используются для доступа к элементам объектов пользовательского интерфейса и их изменения.Properties are often used for accessing and modifying UI (user interface) object members. Например:For example:

int width = rulerView.MeasuredWidth;
int height = rulerView.MeasuredHeight;
...
rulerView.DrawingCacheEnabled = true;

В этом примере значения ширины и высоты считываются из объекта rulerView путем доступа к его свойствам MeasuredWidth и MeasuredHeight.In this example, width and height values are read from the rulerView object by accessing its MeasuredWidth and MeasuredHeight properties. Когда эти свойства считываются, значения из их связанных (но скрытых) значений полей извлекаются в фоновом режиме и возвращаются вызывающему.When these properties are read, values from their associated (but hidden) field values are fetched behind the scenes and returned to the caller. В объекте rulerView значения ширины и высоты могут храниться в одной единице измерения (например, пикселях) и мгновенно преобразовываться в другие единицы измерения (например, миллиметры) при получении доступа к свойствам MeasuredWidth и MeasuredHeight.The rulerView object may store width and height values in one unit of measurement (say, pixels) and convert these values on-the-fly to a different unit of measurement (say, millimeters) when the MeasuredWidth and MeasuredHeight properties are accessed.

У объекта rulerView также есть свойство с именем DrawingCacheEnabled. В примере кода этому свойству задается значение true для включения кэша документа в rulerView.The rulerView object also has a property called DrawingCacheEnabled – the example code sets this property to true to enable the drawing cache in rulerView. В фоновом режиме связанное скрытое поле обновляется новым значением, и, возможно, изменяются другие аспекты состояния rulerView.Behind the scenes, an associated hidden field is updated with the new value, and possibly other aspects of rulerView state are modified. Например, если свойству DrawingCacheEnabled задано значение false, представление rulerView может также удалить все сведения о кэше документа, накопленные в объекте.For example, when DrawingCacheEnabled is set to false, rulerView may also erase any drawing cache information already accumulated in the object.

Доступ к свойствам может предоставляться для чтения или записи, только для чтения или только для записи.Access to properties can be read/write, read-only, or write-only. Кроме того, вы можете использовать разные модификаторы доступа для чтения и записи.Also, you can use different access modifiers for reading and writing. Например, вы можете определить свойство с открытым доступом на чтение, но частным доступом на запись.For example, you can define a property that has public read access but private write access.

Дополнительные сведения о свойствах C# см. в разделе Свойства.For more information about C# properties, see the Properties topic.

Вызов методов базового классаCalling Base Class Methods

Чтобы вызвать конструктор базового класса в C#, нужно ввести двоеточие (:), затем добавить ключевое слово base и список инициализаторов. Этот вызов конструктора base будет следовать сразу после выходного списка его параметров.To call a base-class constructor in C#, you use a colon (:) followed by the base keyword and an initializer list; this base constructor call is placed immediately after the derived constructor parameter list. Конструктор базового класса вызывается в записи в производный конструктор. Компилятор вставляет вызов в базовый конструктор в начале текста метода.The base-class constructor is called on entry to the derived constructor; the compiler inserts the call to the base constructor at the start of the method body. В следующем фрагменте кода показан базовый конструктор, вызванный из производного конструктора в приложении Xamarin.Android:The following code fragment illustrates a base constructor called from a derived constructor in a Xamarin.Android app:

public class PictureLayout : ViewGroup
{
    ...
    public PictureLayout (Context context)
           : base (context)
    {
        ...
    }
    ...
}

В этом примере класс PictureLayout является производным от класса ViewGroup.In this example, the PictureLayout class is derived from the ViewGroup class. Конструктор PictureLayout, показанный в этом примере, принимает аргумент context и передает его в конструктор ViewGroup через вызов base(context).The PictureLayout constructor shown in this example accepts a context argument and passes it to the ViewGroup constructor via the base(context) call.

Чтобы вызвать метод базового класса в C#, используйте ключевое слово base.To call a base-class method in C#, use the base keyword. Например, приложения Xamarin.Android часто вызывают базовые методы, как показано ниже:For example, Xamarin.Android apps often make calls to base methods as shown here:

public class MainActivity : Activity
{
    ...
    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

В этом случае метод OnCreate, определенный производным классом (MainActivity), вызывает метод OnCreate базового класса (Activity).In this case, the OnCreate method defined by the derived class (MainActivity) calls the OnCreate method of the base class (Activity).

Модификаторы доступаAccess Modifiers

Java и C# поддерживают модификаторы доступа public, private и protected.Java and C# both support the public, private, and protected access modifiers. Однако C# поддерживает два дополнительных модификатора доступа:However, C# supports two additional access modifiers:

  • internal  — элемент класса доступен только в текущей сборке.internal – The class member is accessible only within the current assembly.

  • protected internal  — элемент класса доступен в определяющей сборке, определяющем классе и производных классах (внутренних и внешних производных классах, к которым у сборки есть доступ).protected internal – The class member is accessible within the defining assembly, the defining class, and derived classes (derived classes both inside and outside the assembly have access).

Дополнительные сведения о модификаторах доступа в C# см. в статье Модификаторы доступа.For more information about C# access modifiers, see the Access Modifiers topic.

Виртуальные методы и методы переопределенияVirtual and Override Methods

Java и C# поддерживают полиморфизм — способность обрабатывать связанные объекты одинаковым образом.Both Java and C# support polymorphism, the ability to treat related objects in the same manner. Для двух языков вы можете использовать ссылку базового класса для ссылки на объект производного класса, а методы производного класса могут переопределять методы базовых классов этого производного класса.In both languages, you can use a base-class reference to refer to a derived-class object, and the methods of a derived class can override the methods of its base classes. Оба языка включают понятие виртуального метода — метода базового класса, который заменяется методом производного класса.Both languages have the concept of a virtual method, a method in a base class that is designed to be replaced by a method in a derived class. Как и Java, C# поддерживает классы и методы abstract.Like Java, C# supports abstract classes and methods.

Однако есть некоторые различия между Java и C#, а именно в объявлении виртуальных методов и их переопределении.However, there are some differences between Java and C# in how you declare virtual methods and override them:

  • В C# методы по умолчанию не виртуальные.In C#, methods are non-virtual by default. Родительские классы должны явно указывать, какие методы нужно переопределить с помощью ключевого слова virtual.Parent classes must explicitly label which methods are to be overridden by using the virtual keyword. И напротив, все методы в Java являются виртуальными методами по умолчанию.By contrast, all methods in Java are virtual methods by default.

  • В C#, чтобы предотвратить переопределение метода, вы просто не указываете ключевое слово virtual.To prevent a method from being overridden in C#, you simply leave off the virtual keyword. В Java же для этого, напротив, нужно указать ключевое слово final.By contrast, Java uses the final keyword to mark a method with "override is not allowed."

  • В производных классах C# должно использоваться ключевое слово override, чтобы явно указать, что виртуальный метод базового класса переопределяется.C# derived classes must use the override keyword to explicitly indicate that a virtual base-class method is being overridden.

Дополнительные сведения о поддержке полиморфизма в C# см. в статье Полиморфизм.For more information about C#'s support for polymorphism, see the Polymorphism topic.

Лямбда-выраженияLambda Expressions

C# позволяет создавать замыкания: встроенные анонимные методы, с помощью которых можно получить доступ к состоянию метода, в который они вложены.C# makes it possible to create closures: inline, anonymous methods that can access the state of the method in which they are enclosed. Используя лямбда-выражения, вы можете написать меньше строк кода для реализации функций, которые в Java требуют большого количества строк кода.Using lambda expressions, you can write fewer lines of code to implement the same functionality that you might have implemented in Java with many more lines of code.

Лямбда-выражения позволяют пропустить дополнительный код подготовки, связанный с созданием одноразового или анонимного класса, который используется в Java. Вместо этого, вы можете просто написать бизнес-логику своего кода метода в строке.Lambda expressions make it possible for you to skip the extra ceremony involved in creating a one-time-use class or anonymous class as you would in Java – instead, you can just write the business logic of your method code inline. Кроме того, так как у лямбда-выражений есть доступ к переменным в окружающем методе, вам не нужно создавать длинный список параметров для передачи состояния в свой код метода.Also, because lambdas have access to the variables in the surrounding method, you don't have to create a long parameter list to pass state to your method code.

В C# лямбда-выражения создаются с помощью оператора =>, как показано ниже:In C#, lambda expressions are created with the => operator as shown here:

(arg1, arg2, ...) => {
    // implementation code
};

В Xamarin.Android лямбда-выражения часто используются для определения обработчиков событий.In Xamarin.Android, lambda expressions are often used for defining event handlers. Например:For example:

button.Click += (sender, args) => {
    clickCount += 1;    // access variable in surrounding code
    button.Text = string.Format ("Clicked {0} times.", clickCount);
};

В этом примере код лямбда-выражения (код в фигурных скобках) увеличивает количество щелчков и обновляет текст button для указания этого числа.In this example, the lambda expression code (the code within the curly braces) increments a click count and updates the button text to display the click count. Это лямбда-выражение регистрируется с помощью объекта button как обработчик событий щелчка, который будет вызываться каждый раз при нажатии кнопки.This lambda expression is registered with the button object as a click event handler to be called whenever the button is tapped. (Более подробные сведения об обработчиках событий приводятся ниже.) В этом простом примере параметры sender и args не используются кодом лямбда-выражения, но требуются этому выражению для удовлетворения требований к сигнатуре метода для регистрации событий.(Event handlers are explained in more detail below.) In this simple example, the sender and args parameters are not used by the lambda expression code, but they are required in the lambda expression to meet the method signature requirements for event registration. В сущности, компилятор C# преобразует лямбда-выражение в анонимный метод, который вызывается всякий раз при нажатии кнопки.Under the hood, the C# compiler translates the lambda expression into an anonymous method that is called whenever button click events take place.

Дополнительные сведения о лямбда-выражениях C# см. в статье Лямбда-выражения.For more information about C# and lambda expressions, see the Lambda Expressions topic.

Обработка событийEvent Handling

Событие — это способ объекта уведомлять зарегистрированных подписчиков об интересных событиях, связанных с этим объектом.An event is a way for an object to notify registered subscribers when something interesting happens to that object. В отличие от Java, где подписчик обычно реализует интерфейс Listener, содержащий метод обратного вызова, C# обеспечивает поддержку на уровне языка для обработки событий через делегаты.Unlike in Java, where a subscriber typically implements a Listener interface that contains a callback method, C# provides language-level support for event handling through delegates. Делегат подобен объектно-ориентированному указателю типобезопасной функции, который инкапсулирует ссылку на объект и маркер метода.A delegate is like an object-oriented type-safe function pointer – it encapsulates an object reference and a method token. Если клиентский объект хочет подписаться на событие, он создает делегат и передает его уведомляющему объекту.If a client object wants to subscribe to an event, it creates a delegate and passes the delegate to the notifying object. Когда происходит событие, уведомляющий объект вызывает метод, представленный объектом делегата, уведомляя подписавшийся клиентский объект о событии.When the event occurs, the notifying object invokes the method represented by the delegate object, notifying the subscribing client object of the event. В C# обработчики событий — это по сути методы, вызываемые через делегаты.In C#, event handlers are essentially nothing more than methods that are invoked through delegates.

Дополнительные сведения о делегатах см. в статье Делегаты.For more information about delegates, see the Delegates topic.

В C# события являются многоадресными. Это означает, что о возникновении события могут быть уведомлены несколько прослушивателей.In C#, events are multicast; that is, more than one listener can be notified when an event takes place. Это различие наблюдается при рассмотрении синтаксических отличий между регистрацией событий в Java и C#.This difference is observed when you consider the syntactical differences between Java and C# event registration. В Java вы вызываете SetXXXListener для регистрации уведомлений о событиях. В C# вы используете оператор += для регистрации уведомлений о событиях путем "добавления" своего делегата в список прослушивателей событий.In Java you call SetXXXListener to register for event notifications; in C# you use the += operator to register for event notifications by "adding" your delegate to the list of event listeners. В Java для отмены регистрации вы вызываете SetXXXListener, а в C# вы используете оператор -=, чтобы вычесть делегат из списка прослушивателей.In Java, you call SetXXXListener to unregister, while in C# you use the -= to "subtract" your delegate from the list of listeners.

В Xamarin.Android события часто используются для уведомления объектов, если пользователь применяет какие-либо действия к элементу управления пользовательского интерфейса.In Xamarin.Android, events are often used for notifying objects when a user does something to a UI control. Обычно такой элемент управления содержит элементы, определенные с помощью ключевого слова event. Чтобы подписаться на события из этого элемента управления пользовательского интерфейса, нужно вложить свои делегаты в эти элементы.Normally, a UI control will have members that are defined using the event keyword; you attach your delegates to these members to subscribe to events from that UI control.

Чтобы подписаться на событие, сделайте следующее:To subscribe to an event:

  1. Создайте объект-делегат, который ссылается на метод, который должен вызываться при возникновении события.Create a delegate object that refers to the method that you want to be invoked when the event occurs.

  2. Используйте оператор +=, чтобы вложить делегат в событие, на которое вы подписываетесь.Use the += operator to attach your delegate to the event you are subscribing to.

В следующем примере определяется делегат (с явным использованием ключевого слова delegate) для подписки на событие нажатий кнопки.The following example defines a delegate (with an explicit use of the delegate keyword) to subscribe to button clicks. Этот обработчик нажатия кнопки запускает новое действие:This button-click handler starts a new activity:

startActivityButton.Click += delegate {
    Intent intent = new Intent (this, typeof (MyActivity));
    StartActivity (intent);
};

Однако вы также можете использовать лямбда-выражение для регистрации событий, пропуская ключевое слово delegate.However, you also can use a lambda expression to register for events, skipping the delegate keyword altogether. Например:For example:

startActivityButton.Click += (sender, e) => {
    Intent intent = new Intent (this, typeof (MyActivity));
    StartActivity (intent);
};

В этом примере объект startActivityButton содержит событие, ожидающее делегат с определенной сигнатурой метода: делегат, который принимает аргументы отправителя и события и возвращает пустое значение.In this example, the startActivityButton object has an event that expects a delegate with a certain method signature: one that accepts sender and event arguments and returns void. Однако, чтобы избежать явного определения такого делегата или его метода, мы объявляем сигнатуру метода с помощью (sender, e) и используем лямбда-выражение для реализации тела обработчика события.However, because we don't want to go to the trouble to explicitly define such a delegate or its method, we declare the signature of the method with (sender, e) and use a lambda expression to implement the body of the event handler. Обратите внимание, что нам нужно объявить этот список параметров, даже если параметры sender и e не используются.Note that we have to declare this parameter list even though we aren't using the sender and e parameters.

Важно помнить, что вы можете отказаться от подписки на делегат (через оператор -=), но не можете отказаться от подписки на лямбда-выражение. В противном случае это может привести к утечке памяти.It is important to remember that you can unsubscribe a delegate (via the -= operator), but you cannot unsubscribe a lambda expression – attempting to do so can cause memory leaks. Используйте лямбда-форму регистрации событий, только если обработчик не отменит подписку на событие.Use the lambda form of event registration only when your handler will not unsubscribe from the event.

Как правило, лямбда-выражения используются для объявления обработчиков событий в коде Xamarin.Android.Typically, lambda expressions are used to declare event handlers in Xamarin.Android code. Этот простой способ объявления обработчиков событий может показаться сначала непонятным, но он сокращает время написания и чтения кода.This shorthand way to declare event handlers may seem cryptic at first, but it saves an enormous amount of time when you are writing and reading code. С постоянной практикой вы привыкнете распознавать этот шаблон (который часто встречается в коде Xamarin.Android), сможете уделить больше времени бизнес-логике своего приложения и сократить время изучения синтаксических операций.With increasing familiarity, you become accustomed to recognizing this pattern (which occurs frequently in Xamarin.Android code), and you spend more time thinking about the business logic of your application and less time wading through syntactical overhead.

Асинхронное программированиеAsynchronous Programming

Асинхронное программирование дает возможность повысить общую скорость реагирования приложения.Asynchronous programming is a way to improve the overall responsiveness of your application. Функции асинхронного программирования позволяют продолжить выполнение оставшихся разделов кода приложения, в то время как часть приложения блокируется длительной операцией.Asynchronous programming features make it possible for the rest of your app code to continue running while some part of your app is blocked by a lengthy operation. Доступ к Интернету, обработка изображений и чтение или запись файлов — примеры операций, которые могут привести к остановке приложения, если оно не написано с использованием асинхронного программирования.Accessing the web, processing images, and reading/writing files are examples of operations that can cause an entire app to appear to freeze up if it is not written asynchronously.

C# обеспечивает поддержку (на уровне языка) асинхронного программирования с помощью ключевых слов async и await.C# includes language-level support for asynchronous programming via the async and await keywords. Эти языковые функции позволяют легко писать код, который выполняет длительные задачи без блокирования основного потока приложения.These language features make it very easy to write code that performs long-running tasks without blocking the main thread of your application. Коротко говоря, вы используете в методе ключевое слово async, чтобы указать, что код в этом методе должен выполняться асинхронно, а не блокировать поток вызывающего.Briefly, you use the async keyword on a method to indicate that the code in the method is to run asynchronously and not block the caller's thread. При вызове методов, помеченных async, будет использоваться ключевое слово await.You use the await keyword when you call methods that are marked with async. Компилятор интерпретирует await как точку, в которой выполнение метода должно переместиться в фоновый поток (задача возвращается вызывающему).The compiler interprets the await as the point where your method execution is to be moved to a background thread (a task is returned to the caller). Когда эта задача завершается, выполнение кода возобновляется в потоке вызывающего в точке await кода, возвращая результаты вызова async.When this task completes, execution of the code resumes on the caller's thread at the await point in your code, returning the results of the async call. По правилам к именам методов, которые выполняются асинхронно, добавляется суффикс Async.By convention, methods that run asynchronously have Async suffixed to their names.

В приложениях Xamarin.Android async и await обычно используются, чтобы освободить поток пользовательского интерфейса для его реагирования на ввод данных пользователем (например, нажатие кнопки Отмена), в то время как длительная операция выполняется в фоновом задании.In Xamarin.Android applications, async and await are typically used to free up the UI thread so that it can respond to user input (such as the tapping of a Cancel button) while a long-running operation takes place in a background task.

В следующем примере обработчик события нажатия кнопки вызывает асинхронную операцию для загрузки изображения из Интернета:In the following example, a button click event handler causes an asynchronous operation to download an image from the web:

downloadButton.Click += downloadAsync;
...
async void downloadAsync(object sender, System.EventArgs e)
{
    webClient = new WebClient ();
    var url = new Uri ("http://photojournal.jpl.nasa.gov/jpeg/PIA15416.jpg");
    byte[] bytes = null;

    bytes = await webClient.DownloadDataTaskAsync(url);

    // display the downloaded image ...

В этом примере, когда пользователь щелкает элемент управления downloadButton, обработчик событий downloadAsync создает объекты WebClient и Uri для получения изображения из указанного URL-адреса.In this example, when the user clicks the downloadButton control, the downloadAsync event handler creates a WebClient object and a Uri object to fetch an image from the specifed URL. Затем с помощью этого URL-адреса он вызывает метод DownloadDataTaskAsync объекта WebClient для извлечения изображения.Next, it calls the WebClient object's DownloadDataTaskAsync method with this URL to retrieve the image.

Обратите внимание, что перед объявлением метода downloadAsync указывается ключевое слово async для обозначения асинхронного выполнения метода и возвращения задачи.Notice that the method declaration of downloadAsync is prefaced by the async keyword to indicate that it will run asynchronously and return a task. Также обратите внимание, что вызову метода DownloadDataTaskAsync предшествует ключевое слово await.Also note that the call to DownloadDataTaskAsync is preceded by the await keyword. Приложение перемещает выполнение обработчика событий (начиная с точки, где появляется await) в фоновый поток до завершения и возвращения метода DownloadDataTaskAsync.The app moves the execution of the event handler (starting at the point where await appears) to a background thread until DownloadDataTaskAsync completes and returns. Между тем, поток пользовательского интерфейса приложения все еще может реагировать на ввод данных пользователем и запускать обработчики событий для других элементов управления.Meanwhile, the app's UI thread can still respond to user input and fire event handlers for the other controls. После завершения метода DownloadDataTaskAsync (что может занять несколько секунд) выполнение возобновляется, где переменной bytes задается результат вызова метода DownloadDataTaskAsync, а оставшаяся часть кода обработчика событий отображает загруженное изображение в потоке пользовательского интерфейса вызывающего.When DownloadDataTaskAsync completes (which may take several seconds), execution resumes where the bytes variable is set to the result of the call to DownloadDataTaskAsync, and the remainder of the event handler code displays the downloaded image on the caller's (UI) thread.

Обзор async/await в C# см. в статье Асинхронное программирование с использованием ключевых слов async и await.For an introduction to async/await in C#, see the Asynchronous Programming with Async and Await topic. Дополнительные сведения о поддержке в Xamarin функций асинхронного программирования см. в этой статье.For more information about Xamarin support of asynchronous programming features, see Async Support Overview.

Различия в ключевых словахKeyword Differences

Многие ключевые слова, используемые в Java, также используются в C#.Many language keywords used in Java are also used in C#. Имеется также ряд ключевых слов Java, которые имеют аналоги в C#, но с другими именами:There are also a number of Java keywords that have an equivalent but differently-named counterpart in C#, as listed in this table:

JavaJava C#C# ОПИСАНИЕDescription
boolean boolbool Используется для объявления логических значений true и false.Used for declaring the boolean values true and false.
extends : Предшествует классу и интерфейсам наследования.Precedes the class and interfaces to inherit from.
implements : Предшествует классу и интерфейсам наследования.Precedes the class and interfaces to inherit from.
import usingusing Импортирует типы из пространства имен, также используется для создания псевдонима пространства имен.Imports types from a namespace, also used for creating a namespace alias.
final sealedsealed Предотвращает наследование классов. Предотвращает переопределение методов и свойств в производных классах.Prevents class derivation; prevents methods and properties from being overridden in derived classes.
instanceof isis Определяет, совместим ли объект с указанным типом.Evaluates whether an object is compatible with a given type.
native externextern Объявляет метод, который реализуется извне.Declares a method that is implemented externally.
package namespacenamespace Объявляет область для связанного набора объектов.Declares a scope for a related set of objects.
T... params Tparams T Задает параметр метода, который принимает переменное количество аргументов.Specifies a method parameter that takes a variable number of arguments.
super basebase Используется для доступа к элементам родительского класса из производного класса.Used to access members of the parent class from within a derived class.
synchronized locklock Заключает в оболочку критический раздел кода с применением и снятием блокировки.Wraps a critical section of code with lock acquisition and release.

Кроме того, есть много ключевых слов, уникальных для C# и не имеющих аналогов в Java.Also, there are many keywords that are unique to C# and have no counterpart in Java. В коде Xamarin.Android часто используются следующие ключевые слова C# (эту таблицу можно использовать при чтении примера кода Xamarin.Android):Xamarin.Android code often makes use of the following C# keywords (this table is useful to refer to when you are reading through Xamarin.Android sample code):

C#C# ОПИСАНИЕDescription
asas Выполняет преобразования между совместимыми ссылочными типами или типами, допускающими значение null.Performs conversions between compatible reference types or nullable types.
asyncasync Указывает, что метод или лямбда-выражение являются асинхронными.Specifies that a method or lambda expression is asynchronous.
awaitawait Приостанавливает выполнение метода до завершения задачи.Suspends the execution of a method until a task completes.
bytebyte Тип 8-разрядного целого числа без знака.Unsigned 8-bit integer type.
delegatedelegate Используется для инкапсуляции метода или анонимного метода.Used to encapsulate a method or anonymous method.
enumenum Объявляет перечисление, набор именованных констант.Declares an enumeration, a set of named constants.
eventevent Объявляет событие в классе издателя.Declares an event in a publisher class.
fixedfixed Предотвращает перемещение переменной.Prevents a variable from being relocated.
get Определяет метод доступа, который извлекает значение свойства.Defines an accessor method that retrieves the value of a property.
inin Позволяет параметру принимать в универсальном интерфейсе тип с меньшей глубиной наследования.Enables a parameter to accept a less derived type in a generic interface.
objectobject Псевдоним для типа Object в .NET Framework.An alias for the Object type in the .NET framework.
outout Модификатор параметра или объявление параметра универсального типа.Parameter modifier or generic type parameter declaration.
overrideoverride Расширяет или изменяет реализацию наследованного элемента.Extends or modifies the implementation of an inherited member.
partialpartial Объявляет определение, которое нужно разбить на несколько файлов, или отделяет определение метода от его реализации.Declares a definition to be split into multiple files, or splits a method definition from its implementation.
readonlyreadonly Объявляет, что элемент класса можно назначить только во время объявления или с помощью конструктора класса.Declares that a class member can be assigned only at declaration time or by the class constructor.
refref Используется для передачи аргумента по ссылке, а не по значению.Causes an argument to be passed by reference rather than by value.
setset Определяет метод доступа, который устанавливает значение свойства.Defines an accessor method that sets the value of a property.
stringstring Псевдоним для типа String в .NET Framework.Alias for the String type in the .NET framework.
structstruct Тип значения, который инкапсулирует группу связанных переменных.A value type that encapsulates a group of related variables.
typeoftypeof Получает тип объекта.Obtains the type of an object.
varvar Объявляет неявно типизированную локальную переменную.Declares an implicitly-typed local variable.
valuevalue Ссылается на значение, которое код клиента должен присвоить свойству.References the value that client code wants to assign to a property.
virtualvirtual Позволяет переопределить метод в производном классе.Allows a method to be overridden in a derived class.

Взаимодействие с имеющимся кодом JavaInteroperating with Existing Java Code

При наличии функций Java, которые вы не хотите преобразовывать в C#, вы можете повторно использовать имеющиеся библиотеки Java в приложениях Xamarin.Android с помощью двух методов.If you have existing Java functionality that you do not want to convert to C#, you can reuse your existing Java libraries in Xamarin.Android applications via two techniques:

  • Создайте библиотеку привязок Java. При применении этого подхода вы используете инструменты Xamarin для создания программ-оболочек C# вокруг типов Java.Create a Java Bindings Library – Using this approach, you use Xamarin tools to generate C# wrappers around Java types. Эти программы-оболочки называются привязками.These wrappers are called bindings. В результате с помощью вызова этих программ приложение Xamarin.Android может использовать JAR-файл.As a result, your Xamarin.Android application can use your .jar file by calling into these wrappers.

  • Используйте собственный интерфейс Java. Собственный интерфейс Java (JNI) является платформой, которая позволяет приложениям C# вызывать Java-код или реагировать на вызов, выполненный с помощью этого кода.Java Native Interface – The Java Native Interface (JNI) is a framework that makes it possible for C# apps to call or be called by Java code.

Дополнительные сведения об этих методах см. в статье обзора интеграции Java.For more information about these techniques, see Java Integration Overview.

Дополнительные сведенияFor Further Reading

Руководство по программированию C# MSDN содержит основные сведения о языке программирования C#, а в справочнике по C# вы сможете найти определенные функции.The MSDN C# Programming Guide is a great way to get started in learning the C# programming language, and you can use the C# Reference to look up particular C# language features.

В то время, как для изучения языка Java необходимо как минимум ознакомиться с библиотеками класса этого языка, практическая работа с C# требует предварительного знакомства с .NET Framework.In the same way that Java knowledge is at least as much about familiarity with the Java class libraries as knowing the Java language, practical knowledge of C# requires some familiarity with the .NET framework. Обучающий пакет Майкрософт, содержащий ресурсы о переходе на C# и .NET Framework для Java-разработчиков, — оптимальный способ узнать больше о .NET Framework с точки зрения Java (при подробном изучении C#).Microsoft's Moving to C# and the .NET Framework, for Java Developers learning packet is a good way to learn more about the .NET framework from a Java perspective (while gaining a deeper understanding of C#).

Когда вы будете готовы заняться своим первым проектом Xamarin.Android в C#, с помощью серии Hello, Android вы сможете создать свое первое приложение Xamarin.Android и расширить знания основ разработки приложений Android с Xamarin.When you are ready to tackle your first Xamarin.Android project in C#, our Hello, Android series can help you build your first Xamarin.Android application and further advance your understanding of the fundamentals of Android application development with Xamarin.

СводкаSummary

В этой статье содержатся общие сведения о среде программирования C# для Xamarin.Android с точки зрения разработчика Java,This article provided an introduction to the Xamarin.Android C# programming environment from a Java developer's perspective. а также рассматриваются сходства и различия между C# и Java.It pointed out the similarities between C# and Java while explaining their practical differences. В этой статье мы рассмотрели сборки и пространства имен, импорт внешних типов, а также ознакомились с обзором различий в модификаторах доступа, универсальными шаблонами, наследованием классов, вызовом методов базового класса, переопределением методов и обработкой событий.It introduced assemblies and namespaces, explained how to import external types, and provided an overview of the differences in access modifiers, generics, class derivation, calling base-class methods, method overriding, and event handling. Из этого руководства мы узнали о таких функциях C#, недоступных в Java, как свойства, асинхронное программирование с ключевыми словами async/await, лямбда-выражения, делегаты C# и система обработки событий C#.It introduced C# features that are not available in Java, such as properties, async/await asynchronous programming, lambdas, C# delegates, and the C# event handling system. Здесь также содержатся таблицы важных ключевых слов C#, приведены сведения о взаимодействии с имеющимися библиотеками Java и включены ссылки на связанную документацию для дальнейшего изучения.It included tables of important C# keywords, explained how to interoperate with existing Java libraries, and provided links to related documentation for further study.