Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сериализация произвольного класса в XML / 24 сообщений из 24, страница 1 из 1
28.05.2014, 01:00
    #38653952
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Доброго времени суток

Предполагаю для сохранения настроек использовать XML-файлы. Классы настроек могут быть достаточно сложными (с коллекциями и коллекциями в коллекциях, например), причем компонент приложения, который будет заниматься их сериализацией/десериализацией, заранее об этих классах не знает. Имеется ли готовое решение для подобных случаев?
...
Рейтинг: 0 / 0
28.05.2014, 06:38
    #38653995
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Стандартный XmlSerializer:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
public class Foo
{
  public List<Bar> Bars { get; set; }
  public string Name { get; set; }
}

public class Bar
{
  public List<Zot> Zots { get; set; }
  public string Name { get; set; }
}

public class Zot
{
  public string Name { get; set; }
}
....
var f = new Foo
{
  Name = "Foo",
  Bars = new List<Bar>
    {
      new Bar
        {
          Name = "Bar1",
          Zots = new List<Zot> {new Zot {Name = "Zot11"}, new Zot {Name = "Zot12"}}
        },
      new Bar
        {
          Name = "Bar2",
          Zots = new List<Zot> {new Zot {Name = "Zot21"}, new Zot {Name = "Zot22"}}
        }
    }
};
var serializer = new XmlSerializer(typeof (Foo));
var sb = new StringBuilder();
using(var sw = new StringWriter(sb))
using(var xw = XmlWriter.Create(sw, new XmlWriterSettings{Indent = true, IndentChars = "  "}))
  serializer.Serialize(xw, f);
Console.WriteLine(sb);


Результат:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Bars>
    <Bar>
      <Zots>
        <Zot>
          <Name>Zot11</Name>
        </Zot>
        <Zot>
          <Name>Zot12</Name>
        </Zot>
      </Zots>
      <Name>Bar1</Name>
    </Bar>
    <Bar>
      <Zots>
        <Zot>
          <Name>Zot21</Name>
        </Zot>
        <Zot>
          <Name>Zot22</Name>
        </Zot>
      </Zots>
      <Name>Bar2</Name>
    </Bar>
  </Bars>
  <Name>Foo</Name>
</Foo>


Для более тонкой настройки сериализации используются атрибуты .
Только есть пара нюансов:
1. В случае вот такого варианта:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
public class Foo
{
  public IEnumerable<Bar> Bars { get; set; }
  public string Name { get; set; }
}
....
var f = new Foo
{
  Name = "Foo",
  Bars = new List<Bar>
    {
      new Bar
        {
          Name = "Bar1",
          Zots = new List<Zot> {new Zot {Name = "Zot11"}, new Zot {Name = "Zot12"}}
        },
      new Bar
        {
          Name = "Bar2",
          Zots = new List<Zot> {new Zot {Name = "Zot21"}, new Zot {Name = "Zot22"}}
        }
    }.Select(b=>b)
};


конструктор XmlSerializer'а выкинет исключение, у которого внутри будет
Код: plaintext
{"Cannot serialize member FooLib.Foo.Bars of type System.Collections.Generic.IEnumerable`1[[FooLib.Bar, FooLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because it is an interface."}
Т.е. отдаваемые наружу коллекции должны быть классами.
2. XML-сериализация очень тормозная. Я лично вместо нее использую JSON-сериализацию (в т.ч. для настроек) c помощью JSON.Net - получается заметно быстрее XML. Хотя и здесь есть свои нюансы.
...
Рейтинг: 0 / 0
28.05.2014, 15:17
    #38654654
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Сон Веры Павловны,
большое Вам спасибо, буду пробовать.
...
Рейтинг: 0 / 0
28.05.2014, 15:59
    #38654714
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow, есть еще геморои с наследованием классов )
...
Рейтинг: 0 / 0
28.05.2014, 17:59
    #38654884
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Попробовал Json.NET. Сериализируется все, вроде бы, отлично, но с десериализацией проблемы.
Либо нужно указывать тип, в экземпляр которого будут десериализироваться данные ( JsonConvert.DeserializeObject<Type>(json text) ), либо ( JsonConvert.DeserializeObject(json text) )в качестве результата будет получен объект типа Newtonsoft.Json.Linq.JObject, доступ к свойствам которого осуществляется через Newtonsoft.Json.Linq.JObject.Properties().

В общем, хотелось бы, чтобы результат десериализации можно было преобразовывать в объект нужного типа. Это возможно?

Вот пример написанного выше:
...
Рейтинг: 0 / 0
28.05.2014, 18:04
    #38654889
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,

авторЛибо нужно указывать тип, в экземпляр которого будут десериализироваться данныеа в стандартном XML сериализаторе разве не нужно указывать тип в который будет xml десериализовываться? :)
...
Рейтинг: 0 / 0
28.05.2014, 18:40
    #38654922
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Нужно. И этим он мне не нравится.

Есть один вариант - http://www.codeproject.com/Articles/15646/A-Deep-XmlSerializer-Supporting-Complex-Classes-En
но у него свои проблемы: не сериализуется Guid, а также Dictionary<string, object>; наверняка есть еще нюансы. Конечно, можно присобачить костыли, но я надеялся, что есть подобный, но более развитой и работоспособный вариант.

Кроме того, желательно свести до минимума адаптацию структуры сериализуемого класса под конкретный сериализатор . Например, Json.NET для определения свойств, которые не нужно сериализовать, предлагает создавать спецметоды, имена которые зависят от имен соотв. свойств (см. документацию ). Получается, что класс с данными затачивается под конкретное хранилище данных, а это плохо.
...
Рейтинг: 0 / 0
28.05.2014, 18:41
    #38654923
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
про Json.NET правильная ссылка: http://james.newtonking.com/json/help/html/ConditionalProperties.htm
...
Рейтинг: 0 / 0
28.05.2014, 18:44
    #38654928
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,
Вы как то странно себя мучаете. по дефолту Json формат не привязан ни к какому типу net.
ибо пользователем могут быть клиенты и на JS ,php, Java ..ets, равно и серилизатор vcf.
Но везде оставлены плющки net to net, в вашем случе надо было поглубже ознакомится с библиотекой
тынц или http://msdn.microsoft.com/ru-ru/library/system.web.script.serialization.javascriptserializer(v=vs.110).aspx
...
Рейтинг: 0 / 0
28.05.2014, 19:27
    #38654969
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Где-то в степи,

Вас не затруднит уточнить первую ссылку (ака "тынц")?
...
Рейтинг: 0 / 0
28.05.2014, 19:29
    #38654973
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,

пользуйтесь не JsonConvert, а JsonSerializer - у его метода Deserialize есть перегрузки с указанием типа: http://james.newtonking.com/json/help/html/Overload_Newtonsoft_Json_JsonSerializer_Deserialize.htm
либо используете генерик-перегрузку - тогда будет возвращаться уже готовый к употреблению тип, либо перегрузку с указанием Type - ну, тогда надо будет скастить результат Deserialize к нужному типу.
...
Рейтинг: 0 / 0
28.05.2014, 19:30
    #38654974
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public static T DeserializeObject<T>(
	string value


Parameters

value
    Type: System.String
    The JSON to deserialize.

Collapse imageType Parameters

T
    The type of the object to deserialize to.

Return Value
Type: T
The deserialized object from the Json string.
)
...
Рейтинг: 0 / 0
28.05.2014, 19:32
    #38654976
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
...
Рейтинг: 0 / 0
28.05.2014, 19:59
    #38654999
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,
я не пойму, вам надо было вызвать перегрузку дженерика, или у Вас еще какие то проблемы с типом возникают?
Код: c#
1.
var res = JsonConvert.DeserializeObject<ExtendedPrson>(json); 
...
Рейтинг: 0 / 0
28.05.2014, 22:56
    #38655107
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Уважаемые коллеги, возможно, я не совсем верно изложил вопрос. Ниже приведен скелет приложения с описанной проблемой.

Итак, основная сборка приложения - App.exe, класс приложения - App. Все компоненты приложения представлены в классе App интерфейсами, определенными в Base.dll. В нашем приложении имеется два компонента - извещатели об ошибках и критических событиях. Реализации интерфейса извещателя приведены в сборках SmsMessaging.dll и EmailMessaging.dll. Каждый компонент имеет свои настройки, которые надо сохранять (App.Finalize) и загружать (App.Initialize). В прмере настройки простые, в реальности они могут быть очень сложными, причем исполняющей программе конкретные классы настроек (как и самих компонентов) неизвестны.

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

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // Base.dll - separate assembly
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    public interface ISettings
    {
    }

    public interface IComponent
    {
        ISettings Settings { get; }
        void Initialize(ISettings settings);
    }

    public interface INotificationAgent : IComponent
    {
        void Notify(string text);
    }

    public interface IStorage
    {
        void Serialize(string key, object data);
        object Deserialize(string key);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // SmsMessaging.dll - separate assembly
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    public class SmsMessagerSettings : ISettings
    {
        // this is a setting
        public string SourcePhoneNumber { get; set; }        

        // this is a setting
        public List<string> DestPhoneNumbers { get; set; }        
    }

    public class SmsMessager : INotificationAgent
    {
        public ISettings Settings { get; private set; }

        public void Initialize(ISettings settings)
        {
            if (!(settings is SmsMessagerSettings))
                Settings = new SmsMessagerSettings();
            else
                Settings = settings;
        }

        public void Notify(string text)
        {
            var settings = Settings as SmsMessagerSettings;
            
            // send sms-es from settings.SourcePhoneNumber to settings.DestPhoneNumbers
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // EmailMessaging.dll - separate assembly
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    public class EmailMessagerSettings : ISettings
    {
        // this is a setting
        public string SourceEmailAdress { get; set; }

        // this is a setting
        public List<string> DestEmailAdresses { get; set; }        
    }

    public class EmailMessager : INotificationAgent
    {
        public ISettings Settings { get; private set; }

        public void Initialize(ISettings settings)
        {
            if (!(settings is EmailMessagerSettings))
                Settings = new EmailMessagerSettings();

            else
                Settings = settings;
        }

        public void Notify(string text)
        {
            var settings = Settings as SmsMessagerSettings;
            
            // send email letters from settings.SourceEmailAdress to settings.DestEmailAdresses
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // App.exe - main application assembly
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    public class App
    {
        public INotificationAgent ErrorAgent { get; private set; }
        public INotificationAgent CriticalAgent { get; private set; }
        public IStorage SettingsStorage { get; private set; }

        // components init
        public void Initialize()
        {
            // components creation using some kind of IoC framework
            ErrorAgent = IocContainer.Resolve("ErrorAgent") as INotificationAgent;
            CriticalAgent = IocContainer.Resolve("CriticalAgent") as INotificationAgent;
            SettingsStorage = IocContainer.Resolve("SettingsStorage") as IStorage;

            // some storage initialization ...

            // settings loading
            var errorAgentSettings = SettingsStorage.Deserialize("ErrorAgentSettings");
            var criticalAgentSettings = SettingsStorage.Deserialize("CriticalAgentSettings");

            // components initialization
            ErrorAgent.Initialize(errorAgentSettings);
            CriticalAgent.Initialize(criticalAgentSettings);
        }

        // components finalization
        public void Finalize()
        {
            SettingsStorage.Serialize("ErrorAgentSettings", ErrorAgent.Settings);
            SettingsStorage.Serialize("CriticalAgentSettings", CriticalAgent.Settings);
        }
    }



Т.е. в том, чтобы десериализовать объект, зная его тип, проблем нет. Проблема в том, чтобы десериализовать объект неизвестного типа, создав его в процессе десериализации.
...
Рейтинг: 0 / 0
28.05.2014, 23:19
    #38655122
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrowПроблема в том, чтобы десериализовать объект неизвестного типа, создав его в процессе десериализации.

сделать можно, но что с неизвестным типом потом делать?
...
Рейтинг: 0 / 0
29.05.2014, 02:06
    #38655190
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
JohnSparrow,
вообще то решается просто нативными путями


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
 class Program
    {
        static void Main(string[] args)
        {
            var serializer = new JavaScriptSerializer();
            var str = serializer.Serialize(new Person() { LastName = "sdas", FirstName = "fdsfdf" });
            var o = serializer.DeserializeObject(str);
            var res = serializer.ConvertToType(o, typeof(Person));//1
   

        }
    }


    internal class Person : A
    {
        private A _person;
        public Person()
        {
            _person = new A();
            Typename = this.GetType().AssemblyQualifiedName;
        }
        public string FirstName { get; set; }
    }

    internal class A
    {
        public string Typename { get; set; }
        public string[] D = { "sdsd", "fdgdgfg" };
        public string LastName { get; set; }
    }



но у конветера нет метода CanConvertToType, и он отдаст объект типа к которому приводится, если да же граф не подходит.( а не null)
тут могут даже быть некоторые коллизии при совпадении имен переменных.
как бы что в голову пришло:
как вы заметили я создал в типе ( сериализуемом) переменную public string Typename { get; set; }
и уже после серализации вытаскиваю значения из словаря, и наверняка привожу тип к которому нужно.
наверное не очень правильно, но для служебного пользования можно.
Код: c#
1.
2.
 string typename = ((IDictionary<string, object>)o)["Typename"].ToString();
            var res1 = serializer.ConvertToType(o, Type.GetType(typename));//2


Надо порыться и посмотреть в вашей библиотеке может такое возможно через атрибуты только для net...
но вообще что то плохой архитектурой попахивает,если тип десериализации не известен, и приходится рыскать..
...
Рейтинг: 0 / 0
29.05.2014, 03:45
    #38655200
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Где-то в степино вообще что то плохой архитектурой попахивает
+1
И изобретением велосипеда. Существует стандартная система настроек - ей и нужно пользоваться. Для сериализации в JSON нужно написать реализацию TypeConverter, сериализующую объект в стринг, и пометить атрибутом TypeConverter с указанием своего конвертера свой тип (при этом в случае newtonsoft'овского JSON.Net TypeConverter обязательно должен быть унаследован он ComponentConverter, иначе StackOverflowException). После этого объекты будут спокойно сериализоваться-десериализоваться в обычный файл настроек, а все вызовы сериализации-десериализации будут делаться стандартной системой настроек через вышеупомянутый TypeConverter. Ну, а если у вас своя система хранения настроек - реализуйте свой SettingsProvider, в этом нет ничего сложного. Потом этот провайдер указать в свойствах каждой настройки, либо вынести все настройки, сериализуемые особенным образом, в отдельный файл а-ля MyCustomSerializedSettings.settings, и

Код: c#
1.
2.
3.
4.
5.
6.
7.
namespace My.CustomSerializedProperties
{
  [System.Configuration.SettingsProvider(typeof(My.CustomSerializedSettingsProvider))]
  public partial class MyCustomSerializedSettings
  {
  }
}
...
Рейтинг: 0 / 0
29.05.2014, 10:41
    #38655412
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Сон Веры Павловны,
я об этом знал, когда писал о CanConvertToType, посчитал что что так будет спокойней и доходчивей.
это не велосипед есть сериализаторы которые в служебном поле тащат название типа, а в итоге имеем банальное приведение типа
на выходе, если не изменяет память netdatacontractserializer
...
Рейтинг: 0 / 0
29.05.2014, 10:53
    #38655440
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Где-то в степи,

про велосипед относилось к реализации ТСом своего некоего SettingsStorage, т.е. разрабатываемой с нуля системой хранения настроек. А это, повторюсь еще раз, не нужно, достаточно сделать свою реализацию SettingsProvider, и далее пользоваться стандартным механизмом. Поскольку он и сам прописывает тип, в который производится десериализация, и сам сериализует-десериализует, и плюс ко всему - ввиду использования кодогенерации позволяет работать в коде с вполне типизированными настройками.
...
Рейтинг: 0 / 0
29.05.2014, 11:26
    #38655493
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Сон Веры Павловны,
но тут я не знаю, в общем то я то же за SettingsProvider, тем более разграничение по пользователям не плохая вещь.
но наверное чем то не подходит ( приходится клещами вытаскивать), тем более та оперирует контейнерами предположу что основы основ ему знакомы...
...
Рейтинг: 0 / 0
29.05.2014, 11:44
    #38655526
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Сон Веры Павловны,
меня в общем то очень удивила реализация метода serializer.ConvertToType(object, Type )
тип Type должен иметь конструктор по умолчания, со всей логики это полный аут.
ведь приведение типа это нечто иное как финал десирализации ( заполнение объекта типа
значениями из словаря графа) и причем тут открытый конструктор без параметров.
с точки зрения логики это абсолютно до фонаря может быть,( что тип объекта не может иметь закрытого конструктора?)
Надо отдать должное ms при десиреализации везде пользуется своей изюминкой
FormatterServices.GetSafeUninitializedObject(type) или GetUninitializedObject
а тут простой в лоб активатор....
...
Рейтинг: 0 / 0
29.05.2014, 12:29
    #38655614
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
ИзопропилJohnSparrowПроблема в том, чтобы десериализовать объект неизвестного типа, создав его в процессе десериализации.

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

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

Ну что-то типа такого:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<Settings>
<CommonPart>
  ... Здесь общие для всех настройки
<CommonPart>
<SpecificParts>
  <SpecPart fortype="ErrorAgentSettings">!CDATA[....]</SpecPart>
  <SpecPart fortype="CriticalAgentSettings">!CDATA[....]</SpecPart>
</SpecificParts>
</Settings>
...
Рейтинг: 0 / 0
30.05.2014, 21:58
    #38657509
JohnSparrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сериализация произвольного класса в XML
Уважаемые господа, большое спасибо за ответы, особенно про Json.NET и JavaScriptSerializer.
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сериализация произвольного класса в XML / 24 сообщений из 24, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]