Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


.NET глазами дельфийца. C#

Поиск:
.NET глазами дельфийца. C#
опубликовано: 27.03.2002 14:46

Учитывая то, что C#, как и Delphi, выступает одновременно в двух качествах, т.е. с одной стороны, является семантически строго определенным языком программирования и, с другой стороны, использует поставляемые в составе .Net библиотеки классов и компонентов, на первом этапе имеет смысл сконцентрироваться на самом языке программирования, т.к. изучение и сравнительный анализ библиотек классов - гораздо более объемная работа.
.Net глазами дельфийца - первые впечатления.


Введение

При знакомстве с новым языком программирования любого программиста в первую очередь интересует семантическая основа языка, т.е. насколько его выразительные возможности позволяют реализовать привычные логические конструкции.

Учитывая то, что C#, как и Delphi, выступает одновременно в двух качествах, т.е. с одной стороны, является семантически строго определенным языком программирования и, с другой стороны, использует поставляемые в составе .Net библиотеки классов и компонентов, на первом этапе имеет смысл сконцентрироваться на самом языке программирования, т.к. изучение и сравнительный анализ библиотек классов - гораздо более объемная работа.
Чего нет в C#

Отсутствие в C# некоторых вещей обусловлено тем, что C# является <чисто> объектным языком программирования, а Delphi - гибридным. Тем не менее, в C# или имеются, или могут быть легко реализованы самостоятельно практически все семантически эквивалентные конструкции.

Итак, C# не предоставляет следующие возможности (их рассмотрение не вошло в настоящий документ в силу или второстепенного значения, или наличия семантически эквивалентных реализаций в библиотеке CLR):
  • значения параметров по умолчанию
  • множества (set) - реализуется в виде специальных классов в библиотеке CLR
  • диапазоны (subrange) - реализуется в виде специальных классов в библиотеке CLR
  • синонимы простых типов
  • ресурсные строки (resourcestring) - рассматривается как частный случай констант
Более существенные конструкции, которых нет в C#:
  • процедуры, функции
  • глобальные константы
  • глобальные переменные
  • предварительное объявление типов
  • типизованные константы
  • const-параметры
  • указатели
Процедуры, функции

Если считать, что процедуры - это просто функции, которые не возвращают никакого значения, то семантическая нагрузка процедур и функций в Delphi одинакова. Это - выполнение некоторого фрагмента кода, который, возможно, зависит от входных параметров:

Код

procedure A(aParam: integer);
begin
  // ...
end;
function B(aParam: integer): integer;
begin
  // ...
  Result := 0;
end;
A(1);
X := B(1);


В C# семантическим эквивалентом процедур и функций выступают статические методы классов.

Код

// класс-обертка
class Func {
  // статический метод без возвращаемого значения - эквивалент процедуры
  static public void A(int aParam);
  // статический метод - эквивалент функции
  static public int B(int aParam);
}
// вызов процедуры
Func.A(1);
// вызов функции
int X := Func.B(1);



Глобальные константы

Семантическая нагрузка в Delphi - определение значений примитивных типов данных, доступных из любого места кода и неизменяемых в процессе выполнения программы.

Код

const A = 100;
const B = 'строка';
D := A;
ShowMessage(B);


Семантический эквивалент в C# - статические константы.

Код

// класс-обертка
class Const {
  // описание констант
  public const int A = 100;
  public const string B = "строка";
}
// использование констант
int a = Const.A;
MessageBox.Show(Const.B);


Кроме статических констант C# предоставляет механизм статических полей <только для чтения>, который позволяет программисту использовать в качестве констант не только примитивные значения, но и объекты. Пример кода:

Код

// класс-обертка
class Const {
  // число-константа
  public static readonly int A = 1;
  // объект-константа
  public static readonly MyObject Obj = new MyObject();
}



Глобальные переменные

Семантическая нагрузка в Delphi - формирование объектов программы (как примитивных типов, так и сложных), доступных из любого места кода и, возможно, изменяемых в процессе выполнения программы.

Код

var A: integer;
B := A;
A := 1;


Семантический эквивалент в C# - статические поля классов.

Код

// класс-обертка
class Globals {
  // определение статических переменных
  // инициализация по умолчанию = 0
  public static int A;
  // одновременные описание и инициализация
  public static int B = 1;
}
// использование статических переменных
int a = Globals.A;
Globals.A = 1;
int b = Globals.B;
Globals.B = 1;



Предварительное объявление типов

Предварительное объявление типов на самом деле не предусмотрено общей теорией объектно-ориентированного программирования и является частным решением Delphi, направленным на ослабление правила, которое было введено еще в классическом Pascal, - <все типы данных, используемые для построения сложных типов, должны быть или примитивного типа, или описаны до их использования>.

Пример кода на Delphi:

Код

type
  TMyObject1 = class;
  TMyObject2 = class;  
  TMyObject1 = class
    function GetChild(Index: int): TMyObject2;
  end;
  TMyObject2 = class
    property Owner: TMyObject1 read fOwner;
  end;


В C# предописание типов не требуется, т.к. в пределах области видимости классов (обрамляющий класс, пространство имен) порядок объявления несущественен. Такое решение упрощает написание кода:

Код

namespace MyObjects {
  public class TMyObject1 {
    public TMyObject2 GetChild(int Index) { ... }
  }
  public class TMyObject2 {
    public TMyObject1 Owner {
      get { return owner; }
    }
  }
}



Типизированные константы

Типизированные константы в Delphi позволяют хранить не только значения примитивных типов, но и массивы, записи, а также указатели, включая указатели на процедуры и функции:

Код

const A: integer = 1;
const B: array [1..3] of integer = (1, 2, 3);


В C# константы всегда типизированы - как при использовании модификатора const, так и readonly.

В Delphi при использовании директивы компилятора {$J+} (установлено по умолчанию) типизованные константы ведут себя как обычные переменные, которые инициализируются одновременно с описанием, т.е. их значение может быть изменено в ходе выполнения программы:

Код

const A: integer = 1;
X := A;
A := 2;


В C# действуют более строгие правила - если константа, то поменять ее значение невозможно. Если же используется поле <только для чтения>, то его содержимое может быть изменено в контексте объекта:

Код

// класс-обертка
public class Const {
  // число-константа
  public readonly int A = 1;
  // метод изменяет значение поля A
  public void ChangeA(int NewValue) { A = NewValue; }
}


При использовании типизованных констант в качестве инициализируемых переменных в области видимости подпрограммы (метода, процедуры, функции) в Delphi наблюдается недокументированный побочный эффект - данные, записанные в локальные типизованные константы, сохраняются между вызовами подпрограмм:

Код

procedure A;
const B: integer = 0;
begin
  Inc(B);
  ShowMessage(IntToStr(B));
end;
procedure Do;
begin
  A;
  A;
  A;
end;


Результаты вывода: 1, 2, 3

В C# подобный побочный эффект отсутствует. Вообще, стандартизация C# в качестве международного стандарта (ECMA, 2001 год) гарантирует отсутствие побочных эффектов. Поэтому если в программе C# необходимо сохранять некоторое состояние между вызовами подпрограмм (методов), используются стандартные средства, в частности, статические или обыкновенные поля классов.
Const-параметры

В Delphi семантический смысл const-параметров заключается в указании компилятору на возможность оптимизации передачи в функцию (процедуру, метод) неизменяемой ссылки на некоторый объект программы. Так, например, конструкция типа:

Код

procedure A(const S: string);


означает, что в качестве параметра процедуры будет передаваться ссылка на строку (при этом копирования содержимого строки в стек вызова процедуры не происходит). Кроме того, содержимое строки S внутри процедуры изменить нельзя.

В C# не предусмотрено прямого эквивалента const-параметров. Тем не менее, в случае необходимости может быть построена семантически эквивалентная конструкция (аналогия вышеприведенному примеру):

Код

class ReadOnlyString {
  ReadOnlyString(string S) { this.S = S; }
  public readonly string S;
  static void Test(ReadOnlyString s) { Console.Write(s.S); }
  static void Main() {
    string s = "проверка const-параметров";
    ReadOnlyString.Test(new ReadOnlyString(s));
  }
}


Приведенный код иллюстрирует использование классов-<оберток> (т.н. wrappers) и полей <только для чтения>.
Указатели

В Delphi указатели чаще всего используются для <тонкого> управления такими конструкциями, как записи. В частности, при передаче записи в качестве параметра в подпрограмму (процедуру, функцию или метод) происходит побайтное копирование в стек вызова, что может приводить к серьезным накладным расходам. Альтернативное решение - передать в качестве параметра указатель на запись и уже через него внутри подпрограммы получить доступ к элементам записи.

В C# приведенный пример использования указателей на записи более изящно и безопасно реализуется с использованием такой конструкции, как struct. Структуры, как и записи Delphi, могут использоваться для хранения данных и, что более важно с точки зрения семантики, являются объектами, передаваемыми не по ссылке, а по значению.

На самом деле, в C# имеется всего лишь одна возможность использовать указатели - т.н. <небезопасный> код (unsafe code). Особенности его использования определены в стандарте C# достаточно подробно (спецификация C#, приложение A). Однако, необходимо отметить, что в практическом программировании редко приходится использовать указатели для иных целей, кроме оптимизации производительности. Поэтому, учитывая классическое правило <80/20> (<80% пива выпиваются двадцатью процентами населения>, или <80% используемых ресурсов программы приходится на 20% кода>, или <80% объема работы позволяет улучшить производительность только на 20%>), можно акцентироваться на оптимизации кода (в терминах C# - использование небезопасного кода) только при необходимости и только тогда, когда выявлены те самые 20% кода, которые используют 80% ресурсов.
Чего нет в Delphi

Теперь можно рассмотреть те преимущества, которые имеет C# по сравнению с Delphi (порядок перечисления произволен и ни в коей мере не отражает объективные приоритеты или субъективные предпочтения):
  • описание переменных в коде программы
  • возможность передачи в метод переменного количества параметров
  • автоматическое удаление объектов
  • поля классов <только для чтения>
  • индексаторы
  • делегаты
  • возможность реализации модели обработки событий <один-много>
  • цикл foreach
  • статические конструкторы
  • операторы классов
  • структуры
  • атрибуты
  • возможность использовать русский язык для имен объектов программы
Описание переменных в коде программы

Возможность описания переменных в коде программы пришла в C# из C++. Пример кода:

Код

class VarTest {
  static void Main() {
    int a;
    int b, c = 1, d;
    for (int i = 0; i < 10; i++) {
      int x = i * 2;
    }
  }
}


В этом примере продемонстрированы сразу несколько возможностей, отсутствующих в Delphi:
  • описание переменных <по месту>
  • одновременное описание и инициализация переменных
  • локальная область видимости и время жизни переменных
Возможность передачи в метод переменного количества параметров

Пример кода, иллюстрирующий возможность передачи в метод переменного количества параметров:

Код

class Test {
  static void F(params int[] args) {
    // обработка параметров
  }
  static void Main() {
    F();
    F(1);
    F(1, 2);
    F(1, 2, 3);
    F(new int[] {1, 2, 3, 4});
  }
}


В Delphi отсутствие переменного количества параметров можно частично скомпенсировать либо использованием значений параметров по умолчанию, либо передачей в качестве параметра открытого массива.

Однако в первом случае все равно количество параметров ограничено и должно быть определено при написании соответствующей подпрограммы.

Во втором же случае, хотя и наблюдается сходство с C#, есть существенные ограничения:
  • нельзя передать пустой массив (т.е. массив с нулевым количеством элементов)
  • передаваемый массив должен быть создан и заполнен или до вызова подпрограммы, или в момент вызова с помощью конструктора открытого массива
  • неоднородные типы данных поддерживаются только при передаче вариантного открытого массива (впрочем, код разбора такого массива внутри подпрограммы обычно бывает довольно
  • громоздким).
Автоматическое удаление объектов

При программировании в терминах объектов Delphi приходится постоянно учитывать, когда создаются объекты определенного класса и, что еще важнее, кто и когда их удаляет.

Ситуация несколько упрощается при построении визуальных приложений и использовании компонентов - установив компонент на форму (или модуль данных), тем самым мы определяем механизм создания и удаления объектов соответствующего класса, когда форма-владелец создает объект в процессе своей инициализации и удаляет его в момент своего удаления.

При построении невизуальных приложений (например, реализация бизнес-правил на промежуточном слое многоуровневого приложения) можно использовать механизм автоматического удаления COM-объектов или <интерфейсных> объектов (объектов, являющихся наследниками от TInterfacedObject).

Впрочем, необходимо признать, что автоматическое удаление объектов в Delphi реализовано не лучшим образом, т.к.:
  • приходится использовать две или даже три разные модели программирования для визуальных и невизуальных приложений (управление компонентами посредством формы-владельца, интерфейсные объекты, COM-объекты);
  • при использовании COM-объектов отладка не является прозрачной с точки зрения объектной модели Delphi, т.к. в целях совместимости со стандартами OLE приходится соблюдать ряд ограничений, в т.ч. в вопросах генерации ошибок, совместимых с COM.
Более того, <стандартные> объекты Delphi, которые часто используются при построении прикладных объектов, например, списки, стеки, битовые массивы и пр., не поддерживают механизм автоматического удаления, поэтому на практике приходится или использовать смешанную модель, в которой лишь некоторые объекты удаляются автоматически, или в целях стандартизации кода вообще отказываться от автоматического удаления.

Рассмотрим простую семантическую конструкцию - загрузку списка объектов.

В Delphi типичная реализация выглядят примерно так:

Код

procedure LoadList(aList: TObjectList);
begin
  aList.Clear;
  // заполнение списка

end;
. . .
try
  MyObjectList = TObjectList.Create;
  LoadList(MyObjectList);
  // далее - использование объектов из списка
finally
  MyObjectList.Free;
end;


На самом деле из-за ограничений Delphi (TObjectList не может удаляться автоматически) семантика приведенного кода разбивается на две отдельные фазы:
  • создать пустой список объектов
  • заполнить список
В C# аналогичное действие (загрузка списка объектов) реализуется проще и семантически точнее:

Код

class ListLoadTest {
  Collection LoadList() {
    Collection c = new Collection();
    // непосредственная загрузка объектов и добавление их в коллекцию
    return c;
  }
  static void Main() {
    Collection c = LoadList();
    foreach (MyObject in c) {
      // что-то сделать с очередным объектом из списка
    }
  }
}


Строго говоря, в приведенном коде C# даже два преимущества:
  • во-первых, не нужно думать об удалении списка объектов и его элементов (если бы в Delphi для хранения объектов вместо TObjectList использовался бы TList или просто массив, объекты пришлось бы удалять вручную)
  • во-вторых, список объектов создается и заполняется в одном месте.
Таким образом, довольно простая вещь - автоматическое удаление объектов, - позволяет писать более точный (семантически) и понятный код.

Поля классов <только для чтения>

В Delphi для того, чтобы реализовать концепцию <поле только для чтения>, можно использовать свойства (properties), при этом приходится писать нечто подобное:

Код

type
  TMyObject = class
  private
    fData: integer
  public
    // эквивалент поля для чтения
    property Data: integer read fData;
  end;



Поля <только для чтения> в C# введены на уровне языка:

Код

class A {
  public readonly int Data;
}


Разница между (статическими) константами и полями <только для чтения> заключается в том, что если константы могут быть вычислены на стадии компиляции, что справедливо, например, для простых типов, то значения полей <только для чтения> определяются только на стадии выполнения программы.

Это приводит к интересным последствиям. В стандарте C# рассматривается ситуация, когда имеется библиотека и использующая ее программа, компилируемые раздельно. Если в библиотеке использовать константу, то при изменении ее значения (и перекомпиляции библиотеки) нужно перекомпилировать и программу. Если же использовать поле <только для чтения>, то программу перекомпилировать не обязательно, т.к. значение поля определяется на стадии исполнения.
Индексаторы

В Delphi можно реализовать свойство класса типа массив и, установив для него атрибут default, получить некоторое подобие индексатора:

Код

type
  TMyObject = class
  public
    property Items[Index: integer]: string read GetItem; default;
  end;


Тогда в коде можно использовать две эквивалентные конструкции:

Код

S := MyObject.Items[I];
S := MyObject[I];


Вторая строка как раз и демонстрирует основную идею индексаторов C# - возможность обращаться к объекту как к массиву. Однако в Delphi есть существенное ограничение - можно использовать только одно свойство (типа массива) по умолчанию.

В C# можно реализовать произвольное количество индексаторов для класса:

Код

class A {
  int this[int Index] { . . . }
  string this[char Col, int Row] { . . . }
  static void Main() {
    A a = new A();
    for (int i = 0; i < a.Count; i++)
      Console.Writeln(a[i].ToString());
    for (char c = 'a'; c < 'z'; c++)
      for (int r = 1; r < 100; r++)
        Console.Writeln(a[c, r]);
  }
}


Делегаты

В Delphi обработчики событий играют роль делегатов - <делегируют> реальную работу внешнему объекту. Однако из-за того, что Delphi является гибридным языком программирования, встречаются ситуации, когда семантически эквивалентные задачи реализуются разными способами. Так, например, в класса TList при сортировке используется указатель на функцию сравнения элементов:

Код

type TListSortCompare = function (Item1, Item2: Pointer): Integer;
procedure Sort(Compare: TListSortCompare);


Т.е. на самом деле задача сравнения элементов списка также <делегируется> функции, внешней по отношению к объекту TList.

Такая семантическая неоднозначность отнюдь не упрощает программирование.

В C# реализован более общий и однозначный подход - делегаты:

Код

delegate void SimpleDelegate();
class Test {
  static void F() {
    System.Console.WriteLine("Test.F");
  }
  static void Main() {
    SimpleDelegate d = new SimpleDelegate(F);
    d();
  }
}


Причем в качестве реализации делегата может выступать как статический, так и обычный метод.
Возможность реализации модели обработки событий <один-много>

Хотя по умолчанию в C# компоненты реализуют схему подключения обработчиков событий <один-к-одному>, при необходимости может быть реализована модель <один-много>. Основа такой возможности заключается в том, что в качестве обработчиков событий используются делегаты, а их подключение к компоненту реализуется с помощью перегружаемого метода:

Код

class Control: Component {
  // Unique keys for events
  static readonly object mouseDownEventKey = new object();
  static readonly object mouseUpEventKey = new object();
  // Return event handler associated with key
  protected delegate GetEventHandler(object key) {...}
  // Add event handler associated with key
  protected void AddEventHandler(object key, Delegate handler) {...}
  // Remove event handler associated with key
  protected void RemoveEventHandler(object key, Delegate handler) {...}
  // MouseDown event
  public event MouseEventHandler MouseDown {
    add { AddEventHandler(mouseDownEventKey, value); }
    remove { RemoveEventHandler(mouseDownEventKey, value); }
  }
  // MouseUp event
  public event MouseEventHandler MouseUp {
    add { AddEventHandler(mouseUpEventKey, value); }
    remove { RemoveEventHandler(mouseUpEventKey, value); }
  }
}


Приведенный код взят из спецификации C# и, хотя выглядит относительно объемным, прозрачно иллюстрирует возможность использования произвольного внутреннего механизма для хранения ссылок на обработчики и подключения произвольного количества внешних обработчиков.
Цикл foreach

Цикл foreach перенят в C# из Visual Basic. Получилась довольно удобная вещь:

Код

class Test {
  static void Main() {
    double[] values = {1.2, 2.3, 3.4, 4.5};
    foreach (double elementValue in values)
      Console.Write("{0} ", elementValue);
  }
}


Семантически аналогичный код в Delphi выглядит более громоздким из-за необходимости использовать итератор (переменная I), а также (в общем случае) вычислять границы массива:

Код

procedure A;
const Values: array [1..4] of double = (1.2, 2.3, 3.4, 4.5);
var I: integer;
begin
  for I := Low(Values) to High(Values) do
    ShowMessage(FloatToStr(Values[I]));
end;


Статические конструкторы

Некоторый семантический аналог статическим конструкторам в Delphi - секция initialize.

К сожалению, в Delphi порядок вызова секций initialize соответствует порядку подключения модулей. Такая практика может приводить к неожиданным ошибкам - первоначально рассчитывая на конкретный порядок подключения модулей, можно случайно в процессе разработки изменить этот порядок и в результате, например, получить обращение к несуществующему или некорректно инициализированному глобальному объекту программы.

C# предоставляет более строгое объектное решение, которое, в частности, позволяет управлять правами доступа:

Код

class A {
  static protected A GlobalA;
  static A() { GlobalA = new A; }
}


В C# порядок работы статического конструктора определен только на уровне класса, при наличии же нескольких классов со статическими конструкторами порядок их активизации не фиксирован. Такой подход заставляет более тщательно проектировать программу с самого начала и исключает появление в последующем ошибок, аналогичных описанной выше.
Операторы классов

Операторы классов в C# почти эквивалентны операторам классов в C++:

Код

public class Digit {
  byte value;
  public Digit(byte value) {
    if (value < 0 || value > 9) throw new ArgumentException();
    this.value = value;
  }
  public static Digit operator+(Digit a, Digit b) {
    return new Digit(a.value + b.value);
  }
  static public Main() {
    Digit a = new Digit(5);
    Digit b = new Digit(3);
    Digit plus = a + b;
  }
}


По сравнению с C++ в C# строго и однозначно определен порядок реализации пользовательских правил преобразования объектов (преобразования рассматриваются как частный случай операторов).

Примечание: Delphi не имеет механизмов, эквивалентных операторам классов.

Структуры

Структуры в C# аналогичны записям в Delphi в том смысле, что являются данными, передаваемыми по значению, а не по ссылке.

На самом деле семантика структур в C# ближе к классам, за исключением двух основных ограничений:
  • структуры не могут быть абстрактными или содержать абстрактные методы;
  • наследование от структур не поддерживается, в связи с чем методы структур не могут быть виртуальными.
Пример структуры:

Код

struct Point {
 public int x, y;
 public Point(int x, int y) {
    this.x = x;
    this.y = y;
 }
}


Использование структур может как повысить производительность программы (например, при размещении большого количества мелких объектов лучше использовать структуры), так и ухудшить ее (если используется структура, содержащая большие объемы данных, то при передаче ее в качестве параметра будет выполняться лишнее копирование).

Существует эмпирическое правило: если объем данных меньше 16 байт, то для их хранения лучше использовать структуру, если больше - класс.


Атрибуты

Интереснейшая возможность C#, отсутствующая как в Delphi, так и в других наиболее популярных языках программирования (VB, C++, Java), - атрибуты:

Код

[Help("http://www.microsoft.com/.../Class1.htm")]
public class Class1 {
  [Help("http://www.microsoft.com/.../Class1.htm", Topic = "F")]
  public void F() {}
}


Атрибуты похожи на свойства классов Delphi, за исключением того, что их значения устанавливаются на стадии компиляции и в процессе выполнения программы могут быть только считаны. Однако сфера применения атрибутов в поставляемой библиотеке классов CLR весьма широка - от хранения вспомогательной информации декларативного характера до обеспечения совместимости объектов .Net с COM (атрибуты совместимости с COM описаны в приложении B спецификации C#).

Привычки, сформированные под влиянием Delphi, не позволяют даже сразу придумать, для чего можно использовать атрибуты, однако поле деятельности здесь просматривается широкое - от отслеживания версий алгоритмов до контроля за совместимостью программ.
Возможность использовать русский язык для имен объектов программы

В соответствии со спецификацией C# для именования объектов программы (классы, методы, переменные и пр.) используются символы Unicode. Отсюда следует (и реально проверено), что в качестве имен можно использовать русские названия, например:

Код

class ЭлементУчета {
  public int readonly ИнвентарныйНомер;
  public string readonly Наименование;
  public double РассчитатьАмортизацию(int ЛетВЭксплуатации) { ... }
}


Конечно, использование русского языка в коде программы - вопрос спорный. Тем не менее, такая возможность есть. Использовать же ее или нет - вопрос стандартов написания кода в пределах рабочей группы (отдела, предприятия, корпорации).


Заключение

Безусловно, изложенные выше моменты не могут претендовать на абсолютную полноту и глубокую детализацию. Тем не менее, даже на их основе напрашивается естественный вывод - C# является весьма интересным языком программирования, по сравнению с Delphi во многих аспектах даже более мощным и в то же время строгим.
Можно ли на нем писать реальные промышленные задачи?

Если ориентироваться на монолитные приложения в стиле АРМ, то скорее всего нужно более детально проанализировать возможности исполнения программ .Net на конкретной аппаратной платформе (навряд ли Framework.Net сможет работать на 486 с 8М ОЗУ). Если же сделать акцент на многоуровневых приложениях, то C# для реализации промежуточного слоя по сравнению с Delphi является более перспективным кандидатом.

Общий ответ на поставленный вопрос - писать реальные задачи на C# вполне можно, и, скорее всего, даже с меньшими затратами, чем на Delphi.

Трудно ли дельфийцу освоить C#?

Можно утверждать, что нет, т.к. в основе и Delphi, и C# лежит парадигма объектно-ориентированного программирования. Программист, который может в Delphi писать код в терминах объектов, а не только на уровне обработчиков стандартных компонентов, сможет писать и на C#.

Впрочем, C# - не единственный язык, который можно использовать в .Net. Даже в штатной поставке Visual Studio .Net вместе с C# идет C++ и VB.Net, а вообще список языков программирования, реализованных для платформы .Net, уже на сегодня перевалил за десяток. Может быть, и Borland когда-нибудь выпустит Delphi.Net - не зря ведь <отцом> C# является как раз автор Delphi.


Ждать ли дельфийцам выхода Delphi.Net?

На этот вопрос может ответить только фирма Borland. На самом деле, если глубже поразбираться в вопросе декларируемой совместимости программ, написанных на Delphi 6 и Kylix, то оказывается, что о полной совместимости речь не идет - даже у одноименных классов VCL и CLX встречаются разные интерфейсы. Поэтому можно предположить, что Delphi.Net будет совместима с <обычной> Delphi тоже не на все 100%. В чем же тогда будет преимущество Delphi.Net перед тем же C#? Для <закостенелого> дельфийца - только в знакомом синтаксисе. Ну а пока Delphi.Net выйдет в свет, можно и C# освоить (тем более, что его корни лежат в C++, а C++ всегда считался более мощным языком, чем Pascal), или можно на VB.Net писать. Но делать это нужно уже СЕГОДНЯ.


Источник http://www.gotdotnet.ru/LearnDotNet/CSharp/732.aspx
Автор: Pegas
Сайт: http://pegas.vingrad.ru/






Просмотров: 6380

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную