2013-11-26 3 views
4
class A 
{ 
    public int x { get; set; } 
    // other properties 
} 

class S 
{ 
    public A GetA(...); 
} 

доступа Я хотел бы сделать следующее ограничение:
A может быть изменен только внутри S. Когда кто-то получит A через GetA(), он может только получить A 's свойства, а не изменять их.членов C# класса выпуск

я решил сделать новую функцию в S, который возвращает другой объект:

class B 
{ 
    A a; 
    public int x { get { return a.x; } } 
    // replicate other A's properties 
} 

Есть ли лучшее решение?

ответ

7

Вы могли бы сделать интерфейс A только геттеры определены, и вернуться, что с GetA:

public interface IA 
{ 
    int x { get; } 
} 

class A : IA 
{ 
    public int x { get; set; } // nothing stopping you having a setter on the class 
} 

class S 
{ 
    private A a = new A(); // you can call the setter internally on this instance 
    public IA GetA(){ return a; } // when someone gets this thy only get the getter 
} 

Конечно, там ничего не мешает кому-то литейный результат GetA к A, а затем они имеют сеттер - Но вы действительно ничего не можете с этим поделать!

+1

+1 Мы думаем одинаково :). Удалил мой ответ. –

+1

Я думаю, что одним из его требований является то, что * A можно изменить только внутри S *. Но теперь «А» можно изменить везде, если кому-то удастся его получить. Речь идет о том, чтобы сделать его трудным для конечного пользователя, возможно, в нем больше вложено «A». – nawfal

+0

Благодарим вас за комментарий. На самом деле мне нужен A, который должен быть изменен внутри пространства имен, в котором находится S, поэтому я решил использовать private A – Ivan

-1

Другой вариант - вернуть копию A, а не A.

class S 
{ 
    public A GetA() { return a.Clone(); } 
} 

Вы также могли бы сделать A на структуру, которая будет вызывать это произойдет автоматически. Это, конечно, зависит от того, насколько велика или сложна A. В большинстве случаев интерфейс может быть лучше, как описано в ответе Джемика.

+1

Downvoters прокомментировали? – Rotem

+2

Я не сделал ничего, но я думаю, что вы неправильно поняли вопрос. Важная часть, которую вы пропустили «Когда кто-то получает A через GetA(), он может получить только свойства A, а не изменять их» - клонирование A не выполняет это требование – Jamiec

+0

@Jamiec. В том смысле, что любые свойства, которые он изменяет на 'A', не распространяются на' A', найденные в 'S', что и требует OP. Если 'A' - это класс, который содержит только два' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' – Rotem

1

Возможно, вложенный класс может также удовлетворить ваши потребности?

public class S 
{ 
    private A ClassA { get; set; } 

    public S() 
    { 
     ClassA = new A(); 
    } 

    private class A 
    { 
     public int TestProperty { get; set; } 
    } 

    public int GetClassATestProperty 
    { 
     get 
     { 
      return this.ClassA.TestProperty; 
     } 
    } 
} 
0

Вы можете изменить свою реализацию A так, чтобы вы вводили режим readonly. После создания экземпляра вы можете установить свойства по мере необходимости. Когда кто-нибудь получит экземпляр, вы можете включить режим readonly. В режиме readonly разработчики должны выдать исключение, например. InvalidOperationException. Чтобы избежать тонны операторов if (IsReadOnly) ...;, вы можете использовать шаблон стратегии, чтобы изменить поведение экземпляра.
В зависимости от ваших потребностей вы также можете создать копию с режимом ReadOnly, активированным после вызова вызывающего объекта. Это позволило бы изменить даже после того, как запрос был запрошен в первый раз.
Преимущество этого интерфейса заключается в том, что вызывающий абонент не может использовать приведение, чтобы получить доступ к сеттерам. Хотя вам не нужно реализовывать интерфейс, реализация режима readonly должна стоить усилий. Это зависит от вашего анализа риска и ущерба.

1

Вы как-то после friend ключевых слов, как на C++. And there is no equivalent in C# sadly.. Я вижу некоторые возможности.

  1. Является S своего рода A? В этом случае наследование может помочь вам, поскольку вы можете ограничить с помощью модификатора protected.

    class A 
    { 
        public int x { get; protected set; } 
    } 
    
    class S : A 
    { 
        public A GetA() { return this; } //or something like that. 
    } 
    
  2. ли A дело только S? В этом случае вы можете сделать A частным внутренним классом до S, как показано Cloud9999Strife.

  3. Вероятно лучший был бы оставить A как абстрактный класс или интерфейс для общественности и есть конкретная реализация этого вложенной в S - сочетание обоих Jamiec-х и ответ Cloud9999Strife в.

    public abstract class A // or interface 
    { 
        public abstract int x { get; } 
    } 
    
    class S 
    { 
        public A GetA() { return AImplInstead(); } 
    
        class AImpl : A 
        { 
         // nothing stopping you having a setter on the class 
         public override int x { get; set; } 
        } 
    } 
    

В сущности, если A могут быть изменены одним родовое класса, то он может быть везде, если не существует связь между A и S. Вот как проектируется C#. Теперь все, что мы можем сделать, это сделать его (то есть модифицировать A) сложным для конечного пользователя. Отображение интерфейса - одна из его частей. Вложенность делает его на один уровень глубже. Имейте в виду, есть также отражение, которое все равно сломает все инкапсуляции.

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