Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Глобальные переменные, константы, процедуры в C#


Автор: wind1 13.10.2008, 19:41
Недавно начал изучать C#, и возникла проблема - непонятно как обмениваться данными между модулями.
В Delphi всё было довольно просто - в модуле объявлялись глобальные переменные, в другом модуле прописывалась строчка uses [имя модуля с глобальными переменными] и всё - через эти переменные можно было без проблем обмениваться данными между модулями.
А как же поступать в C#? Как обмениваться данными, к примеру, между модулями двух форм? Неужели придется делать это через файлы? :(

Автор: Partizan 13.10.2008, 19:47
Ну специально же закрепили тему наверху, чтобы таких вопросов не было =)
В следующий раз смотрите внимательнее smile

http://forum.vingrad.ru/forum/topic-52713.html

Автор: mihryak 14.10.2008, 00:17
глобальные переменные - зло, и в делфи, и в шарпе ;)

Автор: Partizan 14.10.2008, 11:30
mihryak, и не только там )

Автор: elbjarn 14.10.2008, 15:52
Цитата(Partizan @  14.10.2008,  11:30 Найти цитируемый пост)
mihryak, и не только там ) 

категорически не согласен - глобальные переменные полезны там, где они оправданны.

Автор: Partizan 14.10.2008, 17:24
а можно пример, где использование глобальной переменной действительно оправдано?

Автор: elbjarn 14.10.2008, 20:11
Цитата(Partizan @  14.10.2008,  17:24 Найти цитируемый пост)
а можно пример, где использование глобальной переменной действительно оправдано? 

тут вопрос терминологии. в c#, к примеру, глобальных переменных быть не может в принципе - они всегда будут принадлежать какому-то классу. т.е. говоря о глобальных переменных в сишарпе, мы фактически имеем в виду статические общедоступные свойства или поля класса. они используются повсеместно как и в самом фреймворке, так и в многих приложениях. к примеру, мне часто приходится использовать их в качестве полей класса Config, который занимается сохранением и считыванием настроек моего приложения.
в с++, к примеру, без глобальных переменных вообще обойтись трудно - но там объектной моделью часто пренебрегают, предпочитая использование глобальных переменных объектным вызовам. классический пример глобальной переменной там - это errno, доступ к которой обеспечивается общеизвестной GetLastError().

Автор: VK_Techno 14.10.2008, 20:15
Цитата(Partizan @ 14.10.2008,  17:24)
а можно пример, где использование глобальной переменной действительно оправдано?

Паттерны проектирования синглетон или абстрактная фабрика.

Автор: elbjarn 14.10.2008, 20:28
Цитата(VK_Techno @  14.10.2008,  20:15 Найти цитируемый пост)
Паттерны проектирования синглетон или абстрактная фабрика. 

именно, об этом я и говорил, когда упомянул о классе Config, обращение к которому, как правило, выглядит как
Код

string path = Config.Instance.PathToDB;


Автор: PashaPash 14.10.2008, 21:10
VK_Techno, elbjarn, синглтоны - больше зло, чем добро. IMHO, их использование оправдано только для конфигурации и классов типа Application. 
Проблема как раз в в примере:
Код

string path = Config.Instance.PathToDB;

Стандартный способ работы с конфигурацией не подразумевает наличие синглтона, по крайней мере явно:
Код

var someSection = ConfigurationManager.GetSection("appSettings");

Может там внутри и статическая переменная, но она точно не глобальная.

Автор: elbjarn 14.10.2008, 21:24
Цитата(PashaPash @  14.10.2008,  21:10 Найти цитируемый пост)
синглтоны - больше зло, чем добро. IMHO, их использование оправдано только для конфигурации и классов типа Application. 

и тем не менее, это как раз тот пример, когда применение глобальных переменных оправданноsmile.
но кстати не только конфигурации и application. представьте себе, что вы создаете сайт по всем канонам трехзвенной архитектуры. вы стремитесь сделать независимость вашего приложения от БД максимальной. естественно, вы создаете некоторый провайдер данных, что-то вроде MySiteDataProvider, который содержит разные интересные методы или классы (GetLatestNews(), например, и тд). так вот, у вас может быть несколько вариантов таких провайдеров: MySiteDataProviderAccess, унаследованный от общего абстрактного предка, определяет взаимодействие с MS Access; MySiteDataProviderMSSQL - для ms sql, и так далее. 

во всем вашем приложении вы работаете с данными таким образом:
Код

List<News> list = DataProvider.Instance.GetLatestNews();
,
 а реализация DataProvider в данном случае выглядит примерно так:
Код

public class DataProvider
{
  public static Instance 
 { 
    if (в приложении надо использовать БД MS SQL)
      return MySiteDataProviderMSSQL.Instance;
    else (в приложении надо использовать аксесс)
      return MySiteDataProviderAccess.Instance;
 }
}

имхо, очень изящное решение, основанное на пресловутых статических полях и свойствах.

Автор: PashaPash 14.10.2008, 21:46
Цитата(elbjarn @  14.10.2008,  21:24 Найти цитируемый пост)
и тем не менее, это как раз тот пример, когда применение глобальных переменных оправданно

Да, но глобальные - это когда область видимости у объекта - все приложение. Т.е. когда или поле - public (гм), или свойство явно намекает что вернет синглтон (Instance). Стандартная реализация не упоминает синглтоны, хотя они там ес-но есть где-то внутри smile

Цитата(elbjarn @  14.10.2008,  21:24 Найти цитируемый пост)
но кстати не только конфигурации и application. представьте себе, что вы создаете сайт по всем канонам трехзвенной архитектуры. вы стремитесь сделать независимость вашего приложения от БД максимальной.

А вот этот пример как-раз показывает основную проблему синглтонов - нет нормального управления временем жизни. Т.е. создается один Instance на приложение. Что делает очень трудным написание, например, тестов, которые должны работать независимо друг от друга. Пример:
Код

public class DataProvider
{
  public static Instance 
 { 
    if (в приложении надо использовать БД MS SQL)
      return MySiteDataProviderMSSQL.Instance;
    else (в приложении надо использовать аксесс)
      return MySiteDataProviderAccess.Instance;
 }
}

static class NewsService
{
    static GetNews()
    {
       return DataProvider.Instance.GetNews();
    }

    static AddNews()
    {
       DataProvider.Instance.AddNews(new New());
    }
}

static class SomeOtherService
{
    static GetTopNewsmakers()
    {
        NewsService.GetNews.GetAuthors();
    }
}


И вот теперь надо одтельно проверить работу логики GetNews(), AddNews() и GetTopNewsmakers(). Создавать базу перед вызовом каждого теста - тесты никто не будет писать, они будут работать по пол часа. Не создавать - непонятно, сколько должен вернуть GetNews на тестовых данных.

На самом деле такую проблему принято решать с помощью Inversion of Control Containers and the Dependency Injection. Например, в решении от MS - Unity - тест будет выглядеть так: Добавляете в NewsService конструктор с параметром IDataGateway, и пользуетесь в сервисе только пришедшим значением. А в коде, юзающем сервис, пишете:
Код

var container = new UnityContainer();
container.RegisterType<INewsService, NewsService>();
container.RegisterType<IDataGateway, TestDataGateway>();

INewsService service = container.Resolve<INewsService>();
service.AddNews();
Assert(service.GetNews().Count =1)


и тут же в соседнем тесте создаете новый контейнер и в нем проводите опыты с настоящим SomeOtherService. А еще в одном тесте - с настоящим DataGateway.

А для реального приложения пишете в конфиг всю структуру классов, и создаете контейнер для каждой операции.

Автор: mihryak 14.10.2008, 22:37
elbjarn, такие штуки легко и просто решаются конфигом приложения (например, настройка DbProviderFactory)
или способом PashaPash

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)