Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/124: Рейтинг темы: голосов - 124, средняя оценка - 4.75
6 / 6 / 0
Регистрация: 10.02.2009
Сообщений: 140

копирование объектов

12.02.2009, 13:30. Показов 23849. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Подскажите,пожалуйста, как мне сделать копию объекта.
Имеем obj1, хочу сделать obj2==obj1
при присвоении obj2=obj1 присваивается ссылка на первый объект, и при,например, изменении obj2.field1 значение поля меняется и в obj1, а нужна именно копия, с которой можно дальше работать, не беспокоя первый объект. Всем спасибо!
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.02.2009, 13:30
Ответы с готовыми решениями:

Копирование объектов по значению
Знаю, тема уже заезженная Но то ли у меня голова совсем уже не варит, то ли это действительно так сложно: Работаю с Mono.Cecil....

Глубокое копирование объектов с интерфейсами
Подскажите пожалуйста, если класс наследует интерфейсы, то как реализовать его глубокое копирование. Проблема в том что в интерфейсах не...

Копирование объектов List в другой List
Есть ли способ менее топорового копирования объектов одного List'а в другой List? List<Card> OriginalDeck = new List<Card>();...

14
7 / 7 / 3
Регистрация: 05.02.2009
Сообщений: 30
12.02.2009, 14:02
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
using System;
Class MyClass{
int alpha,beta;
public MyClass(int i;int j){
alpha=i;
beta=j;}
Public bool sameAse(MyClass ob){
if(ob.alpha==alpha)&(ob.beta==beta))
return true; else return fales;}
//создание копия обекта
public void copy(MyClass ob){alpha=ob.alpha;
beta=ob.beta;}
public void Show(){
Console.WriteLine("alpha:{0},beta:{1}",alpha,beta);}
}
class PassOb{
public static void Main(){
MyClass ob1=new MyClass(5,6);
MyClass ob2=new MyClass(5,6);
Console.Write("ob1:");
ob1.show();
Console.Write("ob2:");
ob2.show();
if(sameAs(ob2))
Console.WriteLine("ob1 i ob2 imeyut odinakovie znachenie");
else
console.WriteLine("ob1 i ob2 imeyut razlichniye znachenie");
Console.WriteLine();
//Тепер делаем обект ob1 копией ob2
ob1.copy(ob2);
Console.WriteLine("ob1 posle copy:");
ob1.show();
if(ob1.sameAs(ob2))
Console.WriteLine("ob1 i ob2 imeyut odinakovie znachenie");
else
console.WriteLine("ob1 i ob2 imeyut razlichniye znachenie");}}
методы sameAs() и copy() оба принимают в качестве аргумента ссылочный тип MyClass.
sameAs() сравнивает значение alpha i beta....
0
6 / 6 / 0
Регистрация: 10.02.2009
Сообщений: 140
12.02.2009, 14:19  [ТС]
спасибо за ответ, но речь идёт о копировании объекта целиком, особенно важно это в том случае, когда количество свойств велико, в частности объекты, унаследованные от контролов форм
0
 Аватар для _NuClear
27 / 27 / 2
Регистрация: 09.12.2008
Сообщений: 138
12.02.2009, 14:40
а через оператор new пробовал?

Добавлено через 13 минут 26 секунд
в таком случае кажеться лучше использовать структуры
0
6 / 6 / 0
Регистрация: 10.02.2009
Сообщений: 140
12.02.2009, 14:47  [ТС]
как через new?
Myclass obj2=new Myclass(obj1)?
не прокатывает,например, со стеком,стек "переворачивается",приходится дважды "переливать":
Stack<int> st1=new Stack<int>(st2);
st1=new Stack<int>(st1);
тогда работает, но двойная переливка при длине стека за 100 и количестве операций за 100 тысяч круто тормозит прогу, вот и спросил, как просто сделать
st1=st2
так чтоб st1.Pop() итд не трогало st2


Добавлено через 6 минут 3 секунды
Цитата Сообщение от _NuClear Посмотреть сообщение
в таком случае кажеться лучше использовать структуры
не совсем понимаю идею,как использовать?
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
13.02.2009, 02:52
Stack.Clone() пробовали?
Можно попробовать Stack.CopyTo().
0
6 / 6 / 0
Регистрация: 10.02.2009
Сообщений: 140
13.02.2009, 10:36  [ТС]
у дженерика нет Clone(), а CopyTo даёт массив, передавать массив в качестве параметра конструктору ещё дольше чем писать
st1=Stack<int>(st2);
st1=Stack<int>(st1);
интересует вопрос создания копии объекта любой структуры, в тч объектов Windows.Forms
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
13.02.2009, 15:08
Stack<string> numbers = new Stack<string>();
Stack<string> stack2 = new Stack<string>(numbers.ToArray());
Также переворачивает стек, однако используется копии элементов.

Для поддержки клонирования наследуйте свои объекты от ICloneable. Со своей реализацией Clone().
0
Администратор
 Аватар для mik-a-el
87888 / 53209 / 249
Регистрация: 10.04.2006
Сообщений: 13,767
13.02.2009, 15:15
Цитата Сообщение от red_88 Посмотреть сообщение
интересует вопрос создания копии объекта любой структуры, в тч объектов Windows.Forms
PropertyHandler.cs

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
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Diagnostics;
 
namespace MyApplication
{
    public class PropertyHandler
    {
        #region Set Properties
        public static void SetProperties(PropertyInfo[] fromFields,
                                         PropertyInfo[] toFields,
                                         object fromRecord,
                                         object toRecord)
        {
            PropertyInfo fromField = null;
            PropertyInfo toField = null;
 
            try
            {
 
                if (fromFields == null)
                {
                   return;
                }
                if (toFields == null)
                {
                   return;
                }
 
                for (int f = 0; f < fromFields.Length; f++)
                {
 
                    fromField = (PropertyInfo)fromFields[f];
 
                    for (int t = 0; t < toFields.Length; t++)
                    {
 
                        toField = (PropertyInfo)toFields[t];
 
                        if (fromField.Name != toField.Name)
                        {
                            continue;
                        }
 
                        toField.SetValue(toRecord,
                                         fromField.GetValue(fromRecord, null),
                                         null);
                        break;
 
                    }
 
                }
 
            }
            catch (Exception)
            {
                throw;
            }
        }
        #endregion
 
        #region Set Properties
        public static void SetProperties(PropertyInfo[] fromFields,
                                         object fromRecord,
                                         object toRecord)
        {
            PropertyInfo fromField = null;
         
            try
            {
 
                if (fromFields == null)
                {
                    return;
                }
 
                for (int f = 0; f < fromFields.Length; f++)
                {
 
                    fromField = (PropertyInfo)fromFields[f];
 
                    fromField.SetValue(toRecord,
                                       fromField.GetValue(fromRecord, null),
                                       null);
                }
 
            }
            catch (Exception)
            {
                throw;
            }
        }
        #endregion
  
        
    }
}
PropertyHandler Sample For Identical Classes

C#
1
2
3
4
5
6
7
MyClass record = new MyClass();
MyClass newRecord = new MyClass();
PropertyInfo[] fromFields = null;
 
fromFields = typeof(MyClass).GetProperties();
 
PropertyHandler.SetProperties(fromFields, record, newRecord);
PropertyHandler Sample For Similar Classes

C#
1
2
3
4
5
6
7
8
9
MyClass record = new MyClass();
MyOtherClass newRecord = new MyOtherClass();
PropertyInfo[] fromFields = null;
PropertyInfo[] toFields = null;
 
fromFields = typeof(MyClass).GetProperties();
toFields = typeof(MyOtherClass).GetProperties();
 
PropertyHandler.SetProperties(fromFields,toFields,record, newRecord);
Self Validation Methods

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// Some of the code below relies on runtime reflection.  Certain aspects
// of reflection are detrimental to performance.  Where possible, you
// can create static instances of the reflection results.  It will give
// the power without the overhead of using reflection.
 
// Here is a sample business class layer self validation method.
 
 private bool ValidateSave(CellAlignment record)
 {
 
   object[,] properties = null;
   List<string> returnMessages = new List<string>();
 
   try
   {
 
     // Use the .GetFields() method mentioned later in this sample.
 
     properties = this.GetFields(this.GetType());
 
     if (!record.ValidateRequiredProperties(properties,
                                            returnMessages))
     {
        for (int i = 0; i < returnMessages.Count; i++)
        {
           Debug.WriteLine(returnMessages[i]);
        }
        return false;
     }
 
   }
   catch (Exception) { throw;}
   return true;
 
 }
 
 // This code was extracted from the ADO.NET Code Generator mentioned
 // above.
 
 // Here is a sample property to demonstrate how to use the
 // ColumnAttributes class.  It sets this as being required
 // and tells the validator that it is an int data type.
 
 private int cellAlignmentID = 0;
 
 [ColumnAttributes("CellAlignmentID",true,"int")]
 public int CellAlignmentID
 {
   get 
   {
      return cellAlignmentID;
   }
   set 
   { 
      if (value != cellAlignmentID)
      { 
        cellAlignmentID = valuue;
      }
   }
 }
 
// The ColumnAttributes class itself.
 
[AttributeUsage(AttributeTargets.Property,AllowMultiple = true)] 
 public sealed class ColumnAttributes : System.Attribute  
 { 
 
   private string columnName;
   private bool isRequired;
   private string propertyType;
 
   public string ColumnName
   {
     get { return columnName; } 
   }
 
   public bool IsRequired
   {
     get { return isRequired; } 
   }
 
   public string PropertyType
   {
      get { return propertyType; } 
   }
 
   public ColumnAttributes(string columnNameValue,
                           bool isRequiredValue,
                           string propertyTypeValue)
   { 
      columnName = columnNameValue; 
      isRequired = isRequiredValue; 
      propertyType = propertyTypeValue; 
   } 
 
 } 
 
// Here is a method we can use to get an array of
// PropertyInfo objects as well as custom attributes.
// Make sure every class has this in method available
// to run on itself.  The ADO.NET Code Generator has
// this apart of the CustomAttributes.cs that all
// DataObjects inherit.
 
 public object[,] GetFields(Type t) 
 { 
 
   PropertyInfo[] fields = t.GetProperties(); 
   PropertyInfo field; 
   Attribute[] attributes; 
   object[,]  structureInfo = new object[fields.Length,2];  
 
   try 
   { 
      for(int i =0;i<fields.Length;i++) 
      {       
        field = fields[i];
        attributes =  Attribute.GetCustomAttributes(field,
                                           typeof(DataObjects.Tables.ColumnAttributes),
                                           false); 
        structureInfo[i,0] = field; 
        structureInfo[i,1] = attributes; 
      } 
   } 
   catch (Exception) { throw; } 
   return structureInfo; 
 } 
  
 
 public bool ValidateRequiredProperties(object[,] properties,
                                        List<string> returnMessages)
 {
    bool returnValue = true;
    PropertyInfo property;
    Attribute[] attributes;
    ColumnAttributes columnAttribute = null;
 
    try
    {
 
 
      if (properties == null)
      {
        throw new Exception("Please pass in the results of this.GetFields().");
      }
 
      if (returnMessages != null) 
      { 
         returnMessages.Clear(); 
      } 
 
      for (int i = 0; i <= properties.GetUpperBound(0); i++) 
      { 
 
          property = (PropertyInfo)properties[i, 0]; 
          attributes = (Attribute[])properties[i, 1]; 
 
          foreach (Attribute attribute in attributes) 
          { 
 
            columnAttribute = (ColumnAttributes)attribute; 
 
            if (!columnAttribute.IsRequired) 
            { 
              continue; 
            } 
 
            //    Debug.WriteLine(columnAttribute.ColumnName); 
           //     Debug.WriteLine(property.GetValue(this,null)); 
 
           if (!this.ValidateRequiredPropertyInfo(columnAttribute, 
                                                  property)) 
           { 
 
              returnValue = false; 
 
              if (returnMessages != null) 
              { 
                 returnMessages.Add(columnAttribute.ColumnName + " is required.");
              } 
           } 
 
         } 
 
     } 
     } 
     catch (Exception) { throw;}
     return returnValue;
   }   
 
     public bool ValidateRequiredProperties(object[,] properties) 
     { 
        List<string> returnMessages = null; 
 
        try
        {
           return ValidateRequiredProperties(properties,
                                             returnMessages); 
        } 
        catch (Exception) { throw; } 
     } 
 
     public bool ValidateRequiredPropertyInfo(ColumnAttributes columnAttribute, 
                                              PropertyInfo property) 
     { 
        try 
        { 
          switch (columnAttribute.PropertyType.ToLower()) 
          { 
 
              case "int": 
 
                  if ((int)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "int16": 
 
                  if ((Int16)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "int32": 
 
                  if ((Int32)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "int64": 
 
                  if ((Int64)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "uint": 
 
                  if ((uint)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "uint16": 
 
                  if ((UInt16)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "uint32": 
 
                  if ((UInt32)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
              case "uint64": 
 
                  if ((UInt64)property.GetValue(this, 
                                        null) == 0) 
                  { 
                      return false; 
                  } 
                  
                  break; 
 
                case "double": 
 
                   if ((double)property.GetValue(this, 
                                                 null) == 0) 
                   { 
                       return false; 
                   } 
 
                   break; 
 
                 case "float": 
 
                     if ((float)property.GetValue(this, 
                                                  null) == 0) 
                     { 
                          return false; 
                     } 
 
                      break; 
 
                 case "single": 
 
                     if ((Single)property.GetValue(this, 
                                                  null) == 0) 
                     { 
                          return false; 
                     } 
 
                      break; 
 
                  case "string": 
                  
                      if ((string)property.GetValue(this, 
                                                    null) == String.Empty) 
                      {
                          return false; 
                      } 
                      
                      break; 
 
                  case "guid": 
                  
                      if ((Guid)property.GetValue(this, 
                                                  null) == Guid.Empty) 
                      {
                          return false; 
                      } 
                      
                      break;
                      
 
                  default: 
 
                      if (property.GetValue(this, 
                                            null) == null) 
                      { 
                          return false; 
                      } 
                      
                      break; 
              } 
            } 
            catch (Exception) { throw; } 
            return true; 
         }
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
13.02.2009, 17:53
mik-a-el, такой подход подойдет не всегда. Не усмотрел где связывается последний кусок кода к пред идущим. Такое копирование свойств будет работать для встроенных типов (последний кусок кода как раз ведет проверку по встроенным типам, с этим может справиться сам .NET). Если в свойстве лежит ссылка на объект, то в копию объекта в это свойство попадет эта же ссылка. Не удел остаются приватные поля и свойства. Поэтому копирование объекта разумнее переложить на сам объект.
0
Администратор
 Аватар для mik-a-el
87888 / 53209 / 249
Регистрация: 10.04.2006
Сообщений: 13,767
13.02.2009, 18:05
Так это как вариант
Цитата Сообщение от Green Посмотреть сообщение
Не удел остаются приватные поля и свойства. Поэтому копирование объекта разумнее переложить на сам объект.
Тогда лучше через реализацию ICloneable.
0
 Аватар для _NuClear
27 / 27 / 2
Регистрация: 09.12.2008
Сообщений: 138
14.02.2009, 16:49
создания копии объекта любой структуры
я как раз имел в виду что при создании объекта на основе структуры при операции присвоения создается копия объекта а не ссылки на объект. если не то то извините
0
6 / 6 / 0
Регистрация: 10.02.2009
Сообщений: 140
14.02.2009, 20:10  [ТС]
спасибо. я так понимаю, в С# не рекомендуется обращаться напрямую к памяти,но всеже спрошу: есть ли возможность скопировать всю память выделенную под объект и его поля, или же физически поля объекта могут располагаться в различных участках памяти?
0
1923 / 428 / 41
Регистрация: 12.07.2007
Сообщений: 2,062
16.02.2009, 03:29
Объект не храниться в памяти в течении всего времени. Сборщик мусора может переместить его в другой участок. При чем разрешение у программиста никто не спрашивает.

Добавлено через 2 минуты 7 секунд
_NuClear, далеко на структурах не уедете..
0
Мохаммед Али
 Аватар для asd321
131 / 70 / 5
Регистрация: 14.08.2009
Сообщений: 916
02.08.2011, 09:19
ну так и как же создать копию объекта со сложной иерархией ? нету простого рекурсивного метода какого нить?

Добавлено через 15 часов 49 минут
кароче в мсдн написано делать все ручками но с использованием поверхностного копирования, теость для каждого класса прописываем метод
C#
1
2
3
4
        public object Clone()
        {
            return this.MemberwiseClone();
        }
с указанием наследования этого класса
C#
1
2
 public class FigureInfo:ICloneable
    {}
и плюс для каждого вложенног ов наш класс пропиываем соответственно что то типа этого
C#
1
2
3
4
5
6
7
8
 public object Clone(FigureInfo Previous)
        {
//сначала делаем поверхностное копирование всех неиерархичных конструкций
            Previous = (FigureInfo)this.MemberwiseClone();
//затем делаем копирование иерархичных конструкции-в данном случае такая только 1
            Previous.Info = (Coordinats[])this.Info.Clone();
            return Previous;
        }
Добавлено через 2 минуты
плюс - так как это интерфейс то в каждом классе обязательно присутствие метода
C#
1
2
3
4
        public object Clone()
        {
            return this.MemberwiseClone();
        }
,если даже он нам не нужен,можно даже пустым его сделать, иначе будет ругаться
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
02.08.2011, 09:19
Помогаю со студенческими работами здесь

Копирование определенного текста из файла, копирование и вставка в статичную переменную
Доброго вечера. Делаю программу которая бы выводила погоду на сегодня через данные сайта. Завис на передаче данных с сайта. Как можно...

Массив объектов базового класса, позволяющий работать с набором объектов — чтение, вывод
Расширить программы с классами. Каждый разработанный класс считать базовым; для каждого такого класса описать производный класс - массив...

Каковы преимущества инициализации объектов над созданием объектов
какие преимущества инициализации объектов над созданием объектов, с использованием специального конструктора ? получается только-то что...

При инициализации массива объектов в одном методе, этот массив объектов не видно в других методах
static public void Load() { BaseObject objs = new BaseObject; //Этот массив! for (int i = 0; i &lt;...

Создание списка объектов класса с заранее неизвестным именем (именем самих объектов)
Уважаемые программисты, не получается решить такую задачу: требуется создать приложение (в консоли) &quot;клиенты банка&quot;. Есть два...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru