2013-04-30 2 views
0

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

namespace Utility 
{ 
    public class bar 
    { 
     public string name { get; set; } 
     public double weight { get; set; } 
     public int age { get; set;} 
     public List<...> friendInstances; //instantiated at run time 
    } 
} 

    //and now I make a mutable class. 

public class MemorySafe_bar 
{ 
    private readonly string _name; 
    private readonly double _weight; 
    private readonly int _age; 
    private readonly List<...> _friendInstances; 

    public MemorySafe_bar(string name, double weight, int age, 
     List<...> friend Inst) 
    { 
     _name = name; 
     _weight = weight; 
     _age = age; 
     _friendInstances = Inst 
    } 
    //..getters would go here... 

    function() 
    { 
     Utility.bar bar_ex = new bar(); 
     bar_ex.name = "Kathy"; 
     bar_ex.weight = 42.34; 
     bar_ex.age = 10; 
     bar_ex.List<...> friends = new List<...>(); 
     friends.Add(stuff); 

     Utility.MemorySafe_bar = new MemorySafe_bar(
     bar_ex.name, bar_ex.weight, bar_ex.age, friends); 
    } 
} 

Я не верю, что изменяемый объект никогда не будет изменено в будущем с этого момента.

+0

Что именно вы хотели бы объяснить? Также почему бы не просто установить статический класс со статическим конструктором? – Nomad101

+1

Пробовал форматировать свой код, но есть странная функция '()' с неясной областью - пожалуйста, обновите код ... Также добавьте вопрос в сообщение. –

+3

В чем вопрос? Кроме того, если объект должен быть действительно неизменным, все его члены также должны быть неизменными, а это значит, что вы не можете использовать «Список». – svick

ответ

2

Если вы запрашиваете общий/многоразовый метод обертывания любого класса, чтобы быть неизменной версией, на самом деле это невозможно в общем смысле.

Если конкретный класс подвергается его членов, как virtual или abstract (или как interface) вы могли создавать реализации, которые ничего не делают (или бросать исключения) на сеттеров, но это, как правило, быть неожиданным.

В вашем текущем случае я бы сначала обновил конструктор, чтобы взять объект, который вы обертываете, или сделать это с помощью статического метода фабрики. Я также хотел бы сохранить локальную копию friendInstances и возвращать только для чтения перечислимы из него:

public class ReadOnlyBar 
{ 
    public string name { get; private set; } 
    public double weight { get; private set; } 
    public int age { get; private set; } 

    private readonly Friend[] _friendInstances; 

    public IEnumerable<Friend> friendInstances 
    { 
     get 
     { 
      foreach(var friend in _friendInstances) 
       yield return friend; 
     } 
    } 

    public ReadOnlyBar(Bar bar) 
    { 
     this.name = bar.name; 
     this.weight = bar.weight; 
     this.age = bar.age; 
     this._friendInstances = bar.friendInstances.ToArray(); 
    } 
} 

Использование как:

Bar mutableBar = new mutableBar() { name="Kathy", .... }; 
ReadOnlyBar readonlyBar = new ReadOnlyBar(mutableBar); 

Я только сохранил неизменность Bar, используя свойства вместо readonly полей просто в максимально возможной степени соответствовать API-интерфейсу Bar; их можно легко переключить обратно в поля (что будет способствовать обеспечению неизменности костяных кодов в классе). Вы также можете легко переместить создание в статических фабричных методов или методов расширения, так что вы можете получить использование как:

Bar mutableBar = new mutableBar() { name="Kathy", .... }; 
ReadOnlyBar readonlyBar = ReadOnlyBar.Create(mutableBar); 
//or 
ReadOnlyBar readonlyBar = mutableBar.MakeReadOnly(); 

EDIT: Еще один быстрый вариант, если вы хотите сохранить большую часть функциональности/членов List<Friend> и не ухудшать его к IEnumerable, вы могли бы использовать вместо этого:

public ReadOnlyCollection<Friend> friendInstances { get; private set; } 

public ReadOnlyBar(Bar bar) 
{ 
    //other initialization 
    this.friendInstances = bar.friendInstances.ToList().AsReadOnly(); 
} 

Или вы могли бы даже тип, как List<Friend> и в поглотителе возвращают копию внутреннего списка, но это, вероятно, будет немного далеко, и это сбивает с толку собственность для раскрытия по типу «неизменяемого» объекта.

Смежные вопросы