Środowisko Xamarin dla deweloperów języka Java

Jeśli jesteś deweloperem języka Java, możesz wykorzystać swoje umiejętności i istniejący kod na platformie Xamarin, korzystając z zalet ponownego użycia kodu w języku C#. Składnia języka C# jest bardzo podobna do składni języka Java i że oba języki zapewniają bardzo podobne funkcje. Ponadto poznasz funkcje unikatowe dla języka C#, które ułatwią ci tworzenie aplikacji.

Omówienie

Ten artykuł zawiera wprowadzenie do programowania w języku C# dla deweloperów języka Java, koncentrując się przede wszystkim na funkcjach języka C#, które napotkasz podczas tworzenia aplikacji platformy Xamarin.Android. Ponadto w tym artykule wyjaśniono, jak te funkcje różnią się od ich odpowiedników w języku Java i wprowadzono ważne funkcje języka C# (istotne dla platformy Xamarin.Android), które nie są dostępne w języku Java. Dołączono linki do dodatkowych materiałów referencyjnych, dzięki czemu można użyć tego artykułu jako punktu "skokowego" do dalszej analizy języka C# i platformy .NET.

Jeśli znasz język Java, będziesz czuć się natychmiast w domu ze składnią języka C#. Składnia języka C# jest bardzo podobna do składni języka Java — C# to język "klamrowy", taki jak Java, C i C++. Na wiele sposobów składnia języka C# odczytuje się jak nadzbiór składni języka Java, ale z kilkoma nazwami i dodanymi słowami kluczowymi.

Wiele kluczowych cech języka Java można znaleźć w języku C#:

  • Programowanie obiektowe oparte na klasach

  • Silne wpisywanie

  • Obsługa interfejsów

  • Typy ogólne

  • Wyrzucanie elementów bezużytecznych

  • Kompilacja środowiska uruchomieniowego

Język Java i C# są kompilowane w języku pośrednim, który jest uruchamiany w zarządzanym środowisku wykonywania. Zarówno język C#, jak i Java są statycznie typizowane, a oba języki traktują ciągi jako niezmienne typy. Oba języki używają hierarchii klas z jednym rootem. Podobnie jak język Java, język C# obsługuje tylko pojedyncze dziedziczenie i nie zezwala na metody globalne. W obu językach obiekty są tworzone na stercie przy użyciu słowa kluczowego new , a obiekty są wyrzucane z pamięci, gdy nie są już używane. Oba języki zapewniają obsługę formalnych wyjątków z try/catch semantykami. Obie zapewniają obsługę zarządzania wątkami i synchronizacji.

Istnieje jednak wiele różnic między językiem Java i językiem C#. Na przykład:

  • W języku Java można przekazywać parametry tylko według wartości, natomiast w języku C# można przekazywać odwołania, a także według wartości. (Język C# udostępnia ref słowa kluczowe i out do przekazywania parametrów według odwołania; w języku Java nie ma odpowiedników tych parametrów).

  • Język Java nie obsługuje dyrektyw preprocesora, takich jak #define.

  • Język Java nie obsługuje niepodpisanych typów liczb całkowitych, podczas gdy język C# udostępnia niepodpisane typy liczb całkowitych, takie jak ulong, uintushort i byte.

  • Język Java nie obsługuje przeciążenia operatora; W języku C# można przeciążać operatory i konwersje.

  • W instrukcji Języka Java switch kod może należeć do następnej sekcji przełącznika, ale w języku C# koniec każdej switch sekcji musi zakończyć przełącznik (koniec każdej sekcji musi zamknąć się instrukcją break ).

  • W języku Java określasz wyjątki zgłaszane przez metodę ze throws słowem kluczowym, ale język C# nie ma pojęcia sprawdzonych wyjątków — throws słowo kluczowe nie jest obsługiwane w języku C#.

  • Język C# obsługuje zapytanie zintegrowane z językiem (LINQ), które umożliwia używanie zarezerwowanych słów from, selecti where do pisania zapytań względem kolekcji w sposób podobny do zapytań bazy danych.

Oczywiście istnieje wiele innych różnic między językiem C# i Językiem Java, niż opisano w tym artykule. Ponadto zarówno java, jak i C# nadal ewoluują (na przykład Java 8, który nie znajduje się jeszcze w łańcuchu narzędzi systemu Android, obsługuje wyrażenia lambda w stylu C#), więc te różnice zmienią się w czasie. W tym miejscu opisano tylko najważniejsze różnice występujące obecnie przez deweloperów języka Java dla platformy Xamarin.Android.

  • Przejście z języka Java do programowania w języku C# stanowi wprowadzenie do podstawowych różnic między językiem C# i Językiem Java.

  • Funkcje programowania zorientowanego obiektowo przedstawiają najważniejsze różnice cech obiektowo-obiektowe między dwoma językami.

  • Różnice słów kluczowych zawierają tabelę przydatnych odpowiedników słów kluczowych, słów kluczowych tylko w języku C#oraz linki do definicji słów kluczowych języka C#.

Język C# oferuje wiele kluczowych funkcji platformy Xamarin.Android, które nie są obecnie łatwo dostępne dla deweloperów języka Java w systemie Android. Te funkcje mogą pomóc w pisaniu lepszego kodu w krótszym czasie:

  • Właściwości — dzięki systemowi właściwości języka C#można bezpiecznie i bezpośrednio uzyskiwać dostęp do zmiennych składowych bez konieczności pisania metod ustawiających i getter.

  • Wyrażenia lambda — w języku C# można używać metod anonimowych (nazywanych również lambdami), aby wyrazić funkcjonalność bardziej zwięźle i wydajniej. Możesz uniknąć konieczności zapisywania obiektów jednorazowego użycia i przekazać stan lokalny do metody bez konieczności dodawania parametrów.

  • Obsługa zdarzeń — język C# zapewnia obsługę programowania opartego na zdarzeniach, w którym obiekt może zostać zarejestrowany w celu powiadamiania o wystąpieniu zdarzenia zainteresowania. Słowo event kluczowe definiuje mechanizm emisji multiemisji, którego klasa wydawcy może używać do powiadamiania subskrybentów zdarzeń.

  • Programowanie asynchroniczne — funkcje programowania asynchronicznego języka C# (async/await) zachowują elastyczność aplikacji. Obsługa na poziomie języka tej funkcji sprawia, że programowanie asynchroniczne jest łatwe do zaimplementowania i mniej podatne na błędy.

Na koniec platforma Xamarin umożliwia korzystanie z istniejących zasobów Java za pośrednictwem technologii znanej jako powiązanie. Możesz wywołać istniejący kod Java, struktury i biblioteki z języka C#, korzystając z generatorów automatycznych powiązań platformy Xamarin. W tym celu wystarczy utworzyć bibliotekę statyczną w języku Java i uwidocznić ją w języku C# za pomocą powiązania.

Uwaga

Programowanie w systemie Android używa określonej wersji języka Java, która obsługuje wszystkie funkcje języka Java 7 i podzbiór języka Java 8.

Niektóre funkcje wymienione na tej stronie (takie jak var słowo kluczowe w języku C#) są dostępne w nowszych wersjach języka Java (np. var w języku Java 10), ale nadal nie są dostępne dla deweloperów systemu Android.

Przechodzenie z języka Java do programowania w języku C#

W poniższych sekcjach opisano podstawowe różnice między językami C# i Java. w dalszej sekcji opisano różnice obiektowe między tymi językami.

Biblioteki a zestawy

Język Java zwykle pakuje klasy pokrewne w plikach .jar . Jednak w językach C# i .NET bity wstępnie skompilowanego kodu są pakowane do zestawów, które są zwykle pakowane jako pliki .dll . Zestaw jest jednostką wdrożenia kodu C#/.NET, a każdy zestaw jest zwykle skojarzony z projektem języka C#. Zestawy zawierają kod pośredni (IL), który jest kompilowany w czasie just in time w czasie.

Aby uzyskać więcej informacji na temat zestawów, zobacz temat Zestawy i globalna pamięć podręczna zestawów.

Pakiety a przestrzenie nazw

Język C# używa słowa kluczowego namespace do grupowania powiązanych typów. Jest to podobne do słowa kluczowego package Języka Java. Zazwyczaj aplikacja platformy Xamarin.Android będzie znajdować się w przestrzeni nazw utworzonej dla tej aplikacji. Na przykład następujący kod w języku C# deklaruje WeatherApp otokę przestrzeni nazw dla aplikacji do raportowania pogody:

namespace WeatherApp
{
    ...

Importowanie typów

W przypadku używania typów zdefiniowanych w zewnętrznych przestrzeniach nazw te typy są importowane za pomocą using instrukcji (która jest bardzo podobna do instrukcji Języka Java import ). W języku Java możesz zaimportować pojedynczy typ z instrukcją podobną do następującej:

import javax.swing.JButton

Możesz zaimportować cały pakiet Java z instrukcją podobną do następującej:

import javax.swing.*

Instrukcja języka C# using działa w bardzo podobny sposób, ale umożliwia importowanie całego pakietu bez określania symbolu wieloznakowego. Na przykład na początku plików źródłowych platformy Xamarin.Android często zobaczysz serię instrukcji using , jak pokazano w tym przykładzie:

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;

Te instrukcje importuje funkcje z Systemprzestrzeni nazw , Android.App, Android.Contentitp.

Typy ogólne

Zarówno język Java, jak i język C# obsługują typy ogólne, które są symbolami zastępczymi, które umożliwiają podłączenie różnych typów w czasie kompilacji. Jednak typy ogólne działają nieco inaczej w języku C#. W języku Java funkcja wymazywania typów udostępnia informacje o typie tylko w czasie kompilacji, ale nie w czasie wykonywania. Natomiast środowisko uruchomieniowe języka wspólnego platformy .NET (CLR) zapewnia jawną obsługę typów ogólnych, co oznacza, że język C# ma dostęp do informacji o typie w czasie wykonywania. W codziennych programach deweloperskich platformy Xamarin.Android znaczenie tego rozróżnienia nie jest często widoczne, ale jeśli używasz odbicia, ta funkcja będzie zależeć od tej funkcji w celu uzyskania dostępu do informacji o typie w czasie wykonywania.

W środowisku Xamarin.Android często jest widoczna metoda FindViewById ogólna używana do uzyskiwania odwołania do kontrolki układu. Ta metoda akceptuje ogólny parametr typu, który określa typ kontrolki do wyszukania. Na przykład:

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

W tym przykładzie FindViewById kodu pobiera odwołanie do kontrolki TextView zdefiniowanej w układzie jako Etykieta, a następnie zwraca je jako TextView typ.

Aby uzyskać więcej informacji na temat typów ogólnych, zobacz temat Generics (Ogólne). Należy pamiętać, że istnieją pewne ograniczenia dotyczące obsługi platformy Xamarin.Android dla ogólnych klas języka C#; Aby uzyskać więcej informacji, zobacz Ograniczenia.

Funkcje programowania zorientowanego obiektowo

Zarówno java, jak i C# używają bardzo podobnych idiomów programowania obiektowego:

  • Wszystkie klasy są ostatecznie pochodne od pojedynczego obiektu głównego — wszystkie obiekty Java pochodzą z java.lang.Objectklasy , podczas gdy wszystkie obiekty języka C# pochodzą z System.Objectklasy .

  • Wystąpienia klas są typami referencyjnymi.

  • Podczas uzyskiwania dostępu do właściwości i metod wystąpienia należy użyć operatora ".".

  • Wszystkie wystąpienia klas są tworzone na stercie new za pośrednictwem operatora .

  • Ponieważ oba języki używają odzyskiwania pamięci, nie ma możliwości jawnego zwolnienia nieużywanych obiektów (tj. nie ma słowa kluczowego delete , ponieważ istnieje w języku C++).

  • Klasy można rozszerzyć za pomocą dziedziczenia, a oba języki zezwalają tylko na jedną klasę bazową na typ.

  • Można zdefiniować interfejsy, a klasa może dziedziczyć z (tj. implementować) wiele definicji interfejsu.

Istnieją jednak również pewne istotne różnice:

  • Język Java ma dwie zaawansowane funkcje, których język C# nie obsługuje: klasy anonimowe i klasy wewnętrzne. (Jednak język C# zezwala na zagnieżdżanie definicji klas — zagnieżdżone klasy języka C#są podobne do statycznych klas zagnieżdżonych języka Java).

  • Język C# obsługuje typy struktury stylu C (struct), a język Java nie.

  • W języku C#można zaimplementować definicję klasy w osobnych plikach źródłowych przy użyciu słowa kluczowego partial .

  • Interfejsy języka C# nie mogą deklarować pól.

  • Język C# używa składni destruktora w stylu C++, aby wyrazić finalizatory. Składnia różni się od metody języka Java finalize , ale semantyka jest prawie taka sama. (Należy pamiętać, że w języku C#destruktory automatycznie wywołają destruktor klasy bazowej — w przeciwieństwie do języka Java, w którym jest używane jawne wywołanie super.finalize .

Dziedziczenie klas

Aby rozszerzyć klasę w języku Java, należy użyć słowa kluczowego extends . Aby rozszerzyć klasę w języku C#, należy użyć dwukropka (:), aby wskazać wyprowadzenie. Na przykład w aplikacjach platformy Xamarin.Android często są widoczne wyprowadzenia klas przypominające następujący fragment kodu:

public class MainActivity : Activity
{
    ...

W tym przykładzie MainActivityActivity dziedziczy z klasy .

Aby zadeklarować obsługę interfejsu w języku Java, należy użyć słowa kluczowego implements . Jednak w języku C#wystarczy dodać nazwy interfejsów do listy klas do dziedziczenia, jak pokazano w tym fragmentcie kodu:

public class SensorsActivity : Activity, ISensorEventListener
{
    ...

W tym przykładzie SensorsActivity dziedziczy Activity i implementuje funkcje zadeklarowane w interfejsie ISensorEventListener . Należy pamiętać, że lista interfejsów musi pochodzić po klasie bazowej (lub zostanie wyświetlony błąd czasu kompilacji). Zgodnie z konwencją nazwy interfejsów języka C# są poprzedzone wielkimi literami "I"; dzięki temu można określić, które klasy są interfejsami bez wymagania słowa kluczowego implements .

Jeśli chcesz zapobiec dalszemu podklasowaniu klasy w języku C#, poprzedzasz nazwę klasy — w języku Java poprzedzasz nazwę sealed klasy nazwą finalklasy .

Aby uzyskać więcej informacji na temat definicji klas języka C#, zobacz tematy Klasy i dziedziczenie .

Właściwości

W języku Java metody mutatora (setters) i metody inspektora (getters) są często używane do kontrolowania sposobu wprowadzania zmian w składowych klasy, ukrywając i chroniąc te elementy członkowskie przed kodem zewnętrznym. Na przykład klasa systemu Android TextView udostępnia getText metody i setText . Język C# udostępnia podobny, ale bardziej bezpośredni mechanizm znany jako właściwości. Użytkownicy klasy języka C# mogą uzyskać dostęp do właściwości w taki sam sposób, jak w przypadku uzyskiwania dostępu do pola, ale każdy dostęp faktycznie powoduje wywołanie metody przezroczyste dla obiektu wywołującego. Ta metoda "pod okładkami" może implementować skutki uboczne, takie jak ustawianie innych wartości, wykonywanie konwersji lub zmienianie stanu obiektu.

Właściwości są często używane do uzyskiwania dostępu do elementów członkowskich obiektów interfejsu użytkownika (interfejs użytkownika) i modyfikowania ich. Na przykład:

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

W tym przykładzie rulerView wartości szerokości i wysokości są odczytywane z obiektu przez uzyskanie dostępu do jego MeasuredWidth właściwości i MeasuredHeight . Gdy te właściwości są odczytywane, wartości ze skojarzonych (ale ukrytych) wartości pól są pobierane za kulisami i zwracane do obiektu wywołującego. Obiekt rulerView może przechowywać wartości szerokości i wysokości w jednej jednostce miary (np. pikseli) i przekonwertować te wartości na lot do innej jednostki miary (np. milimetrów), gdy MeasuredWidth uzyskuje się dostęp do właściwości i MeasuredHeight .

Obiekt rulerView ma również właściwość o nazwie DrawingCacheEnabled — przykładowy kod ustawia tę właściwość w celu true włączenia pamięci podręcznej rysunku w pliku rulerView. W tle skojarzone pole ukryte jest aktualizowane przy użyciu nowej wartości, a prawdopodobnie inne aspekty rulerView stanu są modyfikowane. Na przykład gdy DrawingCacheEnabled jest ustawiona wartość false, rulerView może również wymazać wszystkie informacje pamięci podręcznej rysunku już zebrane w obiekcie.

Dostęp do właściwości może być tylko do odczytu/zapisu, tylko do odczytu lub zapisu. Ponadto można użyć różnych modyfikatorów dostępu do odczytu i zapisu. Można na przykład zdefiniować właściwość, która ma publiczny dostęp do odczytu, ale prywatny dostęp do zapisu.

Aby uzyskać więcej informacji o właściwościach języka C#, zobacz temat Właściwości .

Wywoływanie metod klasy bazowej

Aby wywołać konstruktor klasy bazowej w języku C#, należy użyć dwukropka (:), a następnie base słowa kluczowego i listy inicjatorów. To base wywołanie konstruktora jest umieszczane bezpośrednio po liście parametrów konstruktora pochodnego. Konstruktor klasy bazowej jest wywoływany we wpisie do konstruktora pochodnego; kompilator wstawia wywołanie do konstruktora podstawowego na początku treści metody. Poniższy fragment kodu ilustruje konstruktor podstawowy wywoływany z konstruktora pochodnego w aplikacji platformy Xamarin.Android:

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

W tym przykładzie PictureLayoutViewGroup klasa pochodzi z klasy . Konstruktor PictureLayout pokazany w tym przykładzie akceptuje context argument i przekazuje go do konstruktora ViewGroup za pośrednictwem wywołania base(context) .

Aby wywołać metodę klasy bazowej w języku C#, użyj słowa kluczowego base . Na przykład aplikacje platformy Xamarin.Android często tworzą wywołania metod bazowych, jak pokazano poniżej:

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

W tym przypadku metoda zdefiniowana OnCreate przez klasę pochodną (MainActivity) wywołuje OnCreate metodę klasy bazowej (Activity).

Modyfikatory dostępu

Języki Java i C# obsługują publicmodyfikatory dostępu , privatei protected . Język C# obsługuje jednak dwa dodatkowe modyfikatory dostępu:

  • internal — Składowa klasy jest dostępna tylko w bieżącym zestawie.

  • protected internal — Składowa klasy jest dostępna w ramach zestawu definiującego, klasy definiującej i klasy pochodne (klasy pochodne zarówno wewnątrz, jak i na zewnątrz zestawu mają dostęp).

Aby uzyskać więcej informacji na temat modyfikatorów dostępu w języku C#, zobacz temat Modyfikatory dostępu.

Metody wirtualne i zastępowane

Zarówno język Java, jak i język C# obsługują polimorfizm, czyli możliwość traktowania powiązanych obiektów w ten sam sposób. W obu językach można użyć odwołania klasy bazowej do odwoływania się do obiektu klasy pochodnej, a metody klasy pochodnej mogą zastąpić metody jej klas bazowych. Oba języki mają koncepcję metody wirtualnej — metody w klasie bazowej, która ma zostać zastąpiona przez metodę w klasie pochodnej. Podobnie jak język Java, język C# obsługuje abstract klasy i metody.

Istnieją jednak pewne różnice między językami Java i C# w zakresie deklarowania metod wirtualnych i zastępowania ich:

  • W języku C#metody są domyślnie niewirtualne. Klasy nadrzędne muszą jawnie oznaczyć, które metody mają zostać zastąpione za pomocą słowa kluczowego virtual . Z kolei wszystkie metody w języku Java są domyślnie metodami wirtualnymi.

  • Aby zapobiec zastąpieniu metody w języku C#, po prostu pozostaw słowo virtual kluczowe . Natomiast język Java używa słowa kluczowego final do oznaczania metody "przesłonięcia nie jest dozwolone".

  • Klasy pochodne języka C# muszą używać słowa kluczowego override , aby jawnie wskazać, że wirtualna metoda klasy bazowej jest zastępowana.

Aby uzyskać więcej informacji na temat obsługi polimorfizmu w języku C#, zobacz temat Polymorphism (Polimorfizm ).

Wyrażenia lambda

Język C# umożliwia tworzenie zamknięć: wbudowane, anonimowe metody, które mogą uzyskiwać dostęp do stanu metody, w której są ujęte. Używając wyrażeń lambda, można napisać mniej wierszy kodu, aby zaimplementować te same funkcje, które mogły zostać zaimplementowane w języku Java z wieloma wierszami kodu.

Wyrażenia lambda pozwalają pominąć dodatkową ceremonię związaną z tworzeniem klasy jednorazowej lub anonimowej, tak jak w języku Java — zamiast tego możesz po prostu napisać logikę biznesową kodu metody w tekście. Ponadto, ponieważ lambdy mają dostęp do zmiennych w otaczającej metodzie, nie trzeba tworzyć długiej listy parametrów, aby przekazać stan do kodu metody.

W języku C#wyrażenia lambda są tworzone za pomocą => operatora , jak pokazano poniżej:

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

W środowisku Xamarin.Android wyrażenia lambda są często używane do definiowania procedur obsługi zdarzeń. Na przykład:

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

W tym przykładzie kod wyrażenia lambda (kod w nawiasach klamrowych) zwiększa liczbę kliknięć i aktualizuje button tekst, aby wyświetlić liczbę kliknięć. To wyrażenie lambda jest rejestrowane z obiektem button jako procedura obsługi zdarzeń kliknięcia, która ma być wywoływana za każdym razem, gdy przycisk zostanie naciśnięty. (Procedury obsługi zdarzeń zostały wyjaśnione bardziej szczegółowo poniżej). W tym prostym przykładzie sender parametry i args nie są używane przez kod wyrażenia lambda, ale są one wymagane w wyrażeniu lambda, aby spełnić wymagania dotyczące podpisu metody na potrzeby rejestracji zdarzeń. Pod maską kompilator języka C# tłumaczy wyrażenie lambda na anonimową metodę wywoływaną za każdym razem, gdy mają miejsce zdarzenia kliknięcia przycisku.

Aby uzyskać więcej informacji o wyrażeniach języka C# i lambda, zobacz temat Lambda Expressions (Wyrażenia lambda).

Obsługa zdarzeń

Zdarzenie jest sposobem powiadamiania zarejestrowanych subskrybentów, gdy coś interesującego dzieje się z tym obiektem. W przeciwieństwie do języka Java, gdzie subskrybent zazwyczaj implementuje interfejs, który zawiera metodę Listener wywołania zwrotnego, język C# zapewnia obsługę na poziomie języka na potrzeby obsługi zdarzeń za pośrednictwem delegatów. Delegat jest jak obiektowy wskaźnik funkcji bezpieczne dla typu — hermetyzuje odwołanie do obiektu i token metody. Jeśli obiekt klienta chce subskrybować zdarzenie, tworzy delegata i przekazuje delegata do obiektu powiadamiania. W przypadku wystąpienia zdarzenia obiekt powiadamiania wywołuje metodę reprezentowaną przez obiekt delegata, powiadamiając o subskrybowaniu obiektu klienta zdarzenia. W języku C# programy obsługi zdarzeń są zasadniczo niczym więcej niż metodami wywoływanymi za pośrednictwem delegatów.

Aby uzyskać więcej informacji na temat delegatów, zobacz temat Delegaty .

W języku C# zdarzenia są multiemisji. Oznacza to, że więcej niż jeden odbiornik może być powiadamiany o wystąpieniu zdarzenia. Ta różnica jest obserwowana, gdy rozważasz różnice składniowe między rejestracją zdarzeń języka Java i języka C#. W języku Java wywołujesz metodę SetXXXListener rejestrowania powiadomień o zdarzeniach. W języku C# operator służy += do rejestrowania powiadomień o zdarzeniach przez dodanie delegata do listy odbiorników zdarzeń. W języku Java wywołujesz metodę SetXXXListener wyrejestrowania, podczas gdy w języku C# używasz -= elementu do "odejmowania" delegata z listy odbiorników.

W środowisku Xamarin.Android zdarzenia są często używane do powiadamiania obiektów, gdy użytkownik wykonuje coś w kontrolce interfejsu użytkownika. Zwykle kontrolka interfejsu użytkownika będzie mieć elementy członkowskie zdefiniowane przy użyciu słowa kluczowego event . Do tych członków dołączasz delegatów do subskrybowania zdarzeń z tej kontrolki interfejsu użytkownika.

Aby zasubskrybować zdarzenie:

  1. Utwórz obiekt delegata, który odwołuje się do metody, którą chcesz wywołać po wystąpieniu zdarzenia.

  2. += Użyj operatora , aby dołączyć pełnomocnika do zdarzenia, do którego subskrybujesz.

W poniższym przykładzie zdefiniowano delegata (z jawnym użyciem słowa kluczowego delegate ) do subskrybowania kliknięć przycisków. Ta procedura obsługi kliknięcia przycisku uruchamia nowe działanie:

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

Można jednak również użyć wyrażenia lambda, aby zarejestrować się pod kątem zdarzeń, pomijając delegate słowo kluczowe całkowicie. Na przykład:

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

W tym przykładzie startActivityButton obiekt ma zdarzenie, które oczekuje delegata z określonym podpisem metody: taki, który akceptuje argumenty nadawcy i zdarzenia i zwraca wartość void. Jednak ponieważ nie chcemy przechodzić do problemu, aby jawnie zdefiniować taki delegat lub jego metodę, deklarujemy podpis metody za pomocą wyrażenia (sender, e) lambda i używamy wyrażenia lambda w celu zaimplementowania treści procedury obsługi zdarzeń. Należy pamiętać, że musimy zadeklarować tę listę parametrów, mimo że nie używamy parametrów sender i e .

Należy pamiętać, że możesz anulować subskrypcję delegata (za pośrednictwem -= operatora), ale nie można anulować subskrypcji wyrażenia lambda — próba wykonania tej czynności może spowodować przecieki pamięci. Użyj formy rejestracji zdarzeń lambda tylko wtedy, gdy program obsługi nie anuluje subskrypcji zdarzenia.

Zazwyczaj wyrażenia lambda służą do deklarowania programów obsługi zdarzeń w kodzie platformy Xamarin.Android. Ten skrócony sposób deklarowania programów obsługi zdarzeń może wydawać się na początku tajemniczy, ale oszczędza ogromną ilość czasu podczas pisania i odczytywania kodu. Dzięki rosnącej znajomości przyzwyczaisz się do rozpoznawania tego wzorca (który występuje często w kodzie platformy Xamarin.Android) i poświęcasz więcej czasu na myślenie o logice biznesowej aplikacji i mniej czasu na wadowanie za pomocą syntactycznego obciążenia.

Programowanie asynchroniczne

Programowanie asynchroniczne to sposób na poprawę ogólnej reakcji aplikacji. Funkcje programowania asynchronicznego umożliwiają kontynuowanie działania pozostałej części kodu aplikacji, gdy część aplikacji jest blokowana przez długotrwałą operację. Uzyskiwanie dostępu do internetu, przetwarzanie obrazów i odczytywanie/zapisywanie plików to przykłady operacji, które mogą spowodować, że cała aplikacja zawiesza się, jeśli nie jest zapisywana asynchronicznie.

Język C# obejmuje obsługę programowania asynchronicznego za pomocą async słów kluczowych i await . Te funkcje językowe ułatwiają pisanie kodu wykonującego długotrwałe zadania bez blokowania głównego wątku aplikacji. Krótko mówiąc, używasz słowa kluczowego async w metodzie, aby wskazać, że kod w metodzie ma być uruchamiany asynchronicznie i nie blokuje wątku wywołującego. Słowo kluczowe jest await używane podczas wywoływania metod oznaczonych znakiem async. Kompilator interpretuje await element jako punkt, w którym wykonanie metody ma zostać przeniesione do wątku w tle (zadanie jest zwracane do wywołującego). Po zakończeniu tego zadania wykonanie kodu zostanie wznowione w wątku obiektu wywołującego w await punkcie kodu, zwracając wyniki async wywołania. Zgodnie z konwencją metody uruchamiane asynchronicznie mają Async sufiksy ich nazw.

W aplikacjach async platformy Xamarin.Android i await są zwykle używane do zwalniania wątku interfejsu użytkownika, dzięki czemu może reagować na dane wejściowe użytkownika (takie jak naciśnięcie przycisku Anuluj ), podczas gdy długotrwała operacja odbywa się w tle.

W poniższym przykładzie procedura obsługi zdarzeń kliknięcia przycisku powoduje asynchroniczną operację pobierania obrazu z sieci 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 ...

W tym przykładzie, gdy użytkownik kliknie kontrolkę downloadButton , downloadAsync program obsługi zdarzeń tworzy WebClient obiekt i Uri obiekt, aby pobrać obraz ze określonego adresu URL. Następnie wywołuje metodę WebClient obiektu DownloadDataTaskAsync za pomocą tego adresu URL, aby pobrać obraz.

Zwróć uwagę, że deklaracja downloadAsync metody klasy jest poprzedzona async słowem kluczowym, aby wskazać, że zostanie uruchomiona asynchronicznie i zwróci zadanie. Należy również zauważyć, że wywołanie metody jest DownloadDataTaskAsync poprzedzone await słowem kluczowym . Aplikacja przenosi wykonywanie programu obsługi zdarzeń (począwszy od punktu, w którym await występuje) do wątku w tle do momentu DownloadDataTaskAsync zakończenia i powrotu. W międzyczasie wątek interfejsu użytkownika aplikacji może nadal reagować na dane wejściowe użytkownika i uruchamiać programy obsługi zdarzeń dla innych kontrolek. Po DownloadDataTaskAsync zakończeniu (co może potrwać kilka sekund), wykonywanie wznawia działanie, w którym bytes zmienna jest ustawiona na wynik wywołania DownloadDataTaskAsyncmetody , a pozostała część kodu procedury obsługi zdarzeń wyświetla pobrany obraz w wątku obiektu wywołującego.

Aby zapoznać się z wprowadzeniem do async/await języka C#, zobacz temat Programowanie asynchroniczne z funkcją Async i Await. Aby uzyskać więcej informacji na temat obsługi platformy Xamarin funkcji programowania asynchronicznego, zobacz Async Support Overview (Omówienie asynchronicznej pomocy technicznej).

Różnice słów kluczowych

Wiele słów kluczowych języka używanych w języku Java jest również używanych w języku C#. Istnieje również wiele słów kluczowych języka Java, które mają równoważny, ale inaczej nazwany odpowiednik w języku C#, jak wymieniono w tej tabeli:

Java C# opis
boolean bool Służy do deklarowania wartości logicznych true i false.
extends : Poprzedza klasę i interfejsy dziedziczone z.
implements : Poprzedza klasę i interfejsy dziedziczone z.
import using Importuje typy z przestrzeni nazw, używane również do tworzenia aliasu przestrzeni nazw.
final sealed Zapobiega wyprowadzaniu klas; zapobiega zastępowaniu metod i właściwości w klasach pochodnych.
instanceof is Ocenia, czy obiekt jest zgodny z danym typem.
native extern Deklaruje metodę zaimplementowaną zewnętrznie.
package namespace Deklaruje zakres powiązanych zestawów obiektów.
T... params T Określa parametr metody, który przyjmuje zmienną liczbę argumentów.
super base Służy do uzyskiwania dostępu do składowych klasy nadrzędnej z poziomu klasy pochodnej.
synchronized lock Opakowuje krytyczną sekcję kodu przy użyciu uzyskiwania blokady i wydawania.

Istnieje również wiele słów kluczowych, które są unikatowe dla języka C# i nie mają odpowiednika w języku Java używanym w systemie Android. Kod platformy Xamarin.Android często używa następujących słów kluczowych języka C# (ta tabela jest przydatna do odwoływania się do odczytywania przykładowego kodu platformy Xamarin.Android):

C# opis
as Wykonuje konwersje między zgodnymi typami referencyjnymi lub typami dopuszczanymi do wartości null.
async Określa, że metoda lub wyrażenie lambda jest asynchroniczne.
await Zawiesza wykonywanie metody do momentu zakończenia zadania.
byte Niepodpisany typ liczby całkowitej 8-bitowej.
delegate Służy do hermetyzacji metody lub metody anonimowej.
enum Deklaruje wyliczenie , zestaw nazwanych stałych.
event Deklaruje zdarzenie w klasie wydawcy.
Stałe Zapobiega przeniesieniu zmiennej.
get Definiuje metodę dostępu, która pobiera wartość właściwości.
w Umożliwia akceptowanie mniej pochodnego typu w interfejsie ogólnym parametru.
object Alias typu obiekt w programie .NET Framework.
out Modyfikator parametrów lub deklaracja parametru typu ogólnego.
override Rozszerza lub modyfikuje implementację dziedziczonego elementu członkowskiego.
partial Deklaruje definicję, która ma zostać podzielona na wiele plików, lub dzieli definicję metody z jej implementacji.
readonly Deklaruje, że składowa klasy może być przypisana tylko w czasie deklaracji lub przez konstruktor klasy.
ref Powoduje przekazanie argumentu przez odwołanie, a nie przez wartość.
set Definiuje metodę dostępu, która ustawia wartość właściwości.
string Alias typu Ciąg w programie .NET Framework.
struct Typ wartości, który hermetyzuje grupę powiązanych zmiennych.
typeof Uzyskuje typ obiektu.
var Deklaruje niejawnie typizowanej zmiennej lokalnej.
wartość Odwołuje się do wartości, którą kod klienta chce przypisać do właściwości.
virtual Umożliwia zastąpienie metody w klasie pochodnej.

Współdziałanie z istniejącym kodem java

Jeśli masz istniejące funkcje języka Java, których nie chcesz konwertować na język C#, możesz ponownie użyć istniejących bibliotek Java w aplikacjach platformy Xamarin.Android za pomocą dwóch technik:

  • Utwórz bibliotekę powiązań Języka Java — za pomocą tego podejścia użyjesz narzędzi platformy Xamarin do generowania otoek języka C# wokół typów języka Java. Te otoki są nazywane powiązaniami. W związku z tym aplikacja Xamarin.Android może używać pliku .jar , wywołując te otoki.

  • Java Native Interfaceinterfejs natywny Języka Java (JNI) to struktura, która umożliwia wywoływanie aplikacji języka C# lub wywoływanie ich przez kod Java.

Aby uzyskać więcej informacji na temat tych technik, zobacz Omówienie integracji języka Java.

Dalsze informacje

Przewodnik programowania w języku C# w witrynie MSDN to doskonały sposób na rozpoczęcie nauki języka programowania w języku C#. W celu wyszukania określonych funkcji języka C# możesz użyć odwołania w języku C#.

W ten sam sposób, że wiedza na temat języka Java jest co najmniej tak samo znana z bibliotek klas Języka Java, jak znajomość języka Java, praktyczna wiedza na temat języka C# wymaga znajomości platformy .NET. Przejście firmy Microsoft do języka C# i programu .NET Framework dla deweloperów języka Java to dobry sposób, aby dowiedzieć się więcej na temat platformy .NET z perspektywy języka Java (przy jednoczesnym uzyskaniu głębszego zrozumienia języka C#).

Gdy wszystko będzie gotowe do rozwiązania swojego pierwszego projektu platformy Xamarin.Android w języku C#, nasza seria Hello, Android może pomóc w utworzeniu pierwszej aplikacji platformy Xamarin.Android i dokładniej zrozumieć podstawy tworzenia aplikacji dla systemu Android za pomocą platformy Xamarin.

Podsumowanie

W tym artykule przedstawiono wprowadzenie do środowiska programowania języka C# platformy Xamarin.Android z perspektywy dewelopera języka Java. Zwrócił on uwagę na podobieństwa między językami C# i Java, wyjaśniając ich praktyczne różnice. Wprowadzono zestawy i przestrzenie nazw, wyjaśniono, jak importować typy zewnętrzne, oraz przedstawiono omówienie różnic w modyfikatorach dostępu, rodzajach, wyprowadzeniu klas, wywoływaniu metod klasy bazowej, zastępowaniu metod i obsłudze zdarzeń. Wprowadzono funkcje języka C#, które nie są dostępne w języku Java, takie jak właściwości, async/await programowanie asynchroniczne, lambdy, delegaty języka C# i system obsługi zdarzeń języka C#. Zawierała ona tabele ważnych słów kluczowych języka C#, wyjaśniono, jak współdziałać z istniejącymi bibliotekami Języka Java i dostarczała linki do powiązanej dokumentacji w celu dalszej analizy.