2009-09-20 5 views
1

У меня есть куча данных, которые я хочу создать в классе, и для каждой переменной я хочу обеспечить определенный набор методов. IE:Дизайн класса C# без использования «внутреннего» или «статического»?

[TypeA] VarA 
[TypeB] VarB 
[TypeC] VarC 

FA1() which is a function of VarA and VarB 
FA2() which is a function of VarA and VarC 

FB1() which is a function of VarB and VarA 
FB2() which is a function of VarB and VarC 
... 

Как будет большое количество переменных (и, следовательно, еще больше функций) Я хочу, чтобы разделить свой исходный код на управляемые куски. Поэтому я ищу автоматический способ гарантировать, что все функции для каждой переменной будут созданы.

У меня есть 3 возможных метода для организации моего кода, и я не очень доволен каждым из них, и я ищу или совет относительно того, какой метод лучше (или даже если я пропустил совершенно другую реализацию метод):

1. Частичный класс

partial class Base 
{ 
} 

partial class Base 
{ 
    [TypeA] VarA; 

    FA1 { .. }; // function of VarA and VarB 
    FA2 { .. }; // function of VarA and VarC 
} 


partial class Base 
{ 
    [TypeB] VarB; 

    FB1 { .. }; // function of VarB and VarA 
    FB2 { .. }; // function of VarB and VarC 
} 

Pros:

  1. Простой
  2. Переменные могут быть доступны только из класса Base.
  3. Если есть две переменные того же типа, то функции для каждой переменной могут выполнять свою собственную функцию по-разному.

Минусы:

  1. не может автоматически обеспечить, чтобы все функции созданы для каждой переменной
  2. Необходимо вручную убедиться, что нет имен столкновений между каждым именем функции.

Обратите внимание, что Cons может быть решена с помощью генератора кода какой-то (может быть время, чтобы узнать T4 ??)


2. Внутренний класс

class Base 
{ 
    internal [ClassA] ObjA = new [ClassA](); 
    internal [ClassB] ObjB = new [ClassB](); 
} 

class [BaseClassA] 
{ 
    public [TypeA] VarA; 

    public virtual F1 { .. }; 
    public virtual F2 { .. }; 
} 

class [ClassA] : [BassClassA] 
{ 
    public override F1 { .. }; // function of VarA and ObjB.VarB 
    public override F2 { .. }; // function of VarA and ObjC.VarC 
} 
... 

Pros :

  1. Иерархия классов предусматривает, что al l создаются и доступны переменные.
  2. Благодаря использованию виртуальных функций можно создавать экземпляра конкретных реализаций функций

Минусы:

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

3.Статические данные

abstract class Data 
{ 
    static [TypeA] VarA; 
    static [TypeB] VarB; 
    ... 
} 

abstract class [BaseClassA] : Data 
{ 
    public virtual F1 { .. }; 
    public virtual F2 { .. }; 
} 

class [ClassA] : [BassClassA] 
{ 
    public override F1 { .. }; // function of VarA and VarB 
    public override F2 { .. }; // function of VarA and VarC 
} 

class Base 
{ 
[ClassA] ObjA = new [ClassA](); 
[ClassB] ObjB = new [ClassB](); 
} 

Плюсы:

  1. Система гарантирует, что все процедуры инстанцируются
  2. Данные не взорвали все вокруг узла
  3. Внутри каждой функции вы можете напрямую ссылаться на другие переменные на решение «частичного класса»

Против:

  1. Использование статического пахнет я только переизобрел глобальные данные.

То, что я хочу, чтобы как-то вишневый выбрать лучшие моменты каждого метода:

  1. Прямой способ доступа к переменным «Частичного класса» и «Статические» методы
  2. Локальные данные метода «Partial class»
  3. Автоматическое внедрение функции «Внутренние» и «Статические» методы.

И я хочу, чтобы избежать:

  1. Отсутствие исполнившего генерации функции в «Частичный класс»
  2. глобальный доступ к данным в «Internal» метод
  3. повторно изобретение глобальных данных в методе «Статический»

Если бы у меня были мои барабанщики, я бы сказал, что я хочу, чтобы как-то применить интерфейс к instan в.п. переменного - как:

[TypeA] VarA : IFunctions; 
[TypeB] VarB : IFunctions; 

И как-то компилятор автоматически генерирует конечные имена функций из имен интерфейсов и vaiable имени.

Таким образом, люди могут предложить, какой из 3 методов они предпочли бы реализовать, или предложить любые другие методы, которые могут подойти.

+1

ow. мозг больно. как формируются данные. – Will

ответ

0

Ваш вопрос во многом не имеет реального контекста и его трудно понять. Вы дали три «ответа» без четкого вопроса (imo.)

Откровенно говоря, если вы хотите убедиться, что каждая переменная, как вы ее называете, имеет связанные методы, вы должны рассмотреть использование интерфейсов и использовать свойства в место полей (поскольку интерфейсы не могут задавать поля.)

interface IAStuff { 
    TypeA AProp { get; } 
    void DoSomethingToA(); 
} 

interface IBStuff { 
    TypeB BProp { get; } 
    void DoSomethingToB(); 
} 

public class Foo : IAStuff, IBStuff { 
    TypeA AProp { get; private set; } 
    TypeB BProp { get; private set; } 

    void DoSomethingToA() { ... } 
    void DoSomethingToB() { ... } 
} 

Если класс объявляет, что он реализует интерфейс, он не имеет никакого выбора, кроме как обеспечить указанные элементы или он не будет компилировать.

Надеется, что это помогает,

-Oisin

+0

Спасибо за ответ, хотя, хотя я и считаю, что у меня есть ясный вопрос, я не собираюсь утверждать, что это обязательно ясно представлено :-) Но что касается вашего ответа, я могу видеть, откуда вы, но как написано I не думайте, что он хорошо масштабируется, поскольку я должен определить интерфейс для каждой переменной (а не только для каждого типа переменной) и, следовательно, по-прежнему вручную поддерживать имена всех методов - что-то, на что я надеюсь уйти. И я не вижу общий интерфейс, помогающий, поскольку это абстрагирует типы, но не имена методов. –

+0

Если вы замените переменную на _class_, возможно, общий интерфейс или базовый класс выполнит трюк. Один мудрый старый кодер однажды сказал мне: если вы не можете заставить его работать, добавьте больше классов ;-) – x0n

+0

, чтобы уточнить, я имею в виду фактор из поля. – x0n

0

Не мог бы вы не использовать предложение 2, но с защитой вместо внутреннего?

+0

Моя первоначальная реакция - нет. Защищенный позволяет получить доступ к элементам из классов, которые производятся из базового класса. Однако в этом случае я использую композицию и не получаю ClassA и ClassB от Base. В результате как ClassA, так и ClassB должны быть скомпилированы независимо от Base, и я не вижу, как это сделать без «внутреннего» –

2

Вы представляете четыре образца кода, «простую» версию, чтобы вы могли объяснить проблему, а затем 3 «лучшие» решения для устранения проблемы. Единственной версией, которая была понятной, была простая версия. Итак, я думаю о бедном разработчике, который должен прийти в следующий год (это может быть вы, забыв, что вы сделали).

Итак, вы могли бы рассмотреть другой механизм в целом для «обеспечения того, чтобы все функции для каждой переменной были созданы». Вы упомянули о готовности использовать T4 для автоматического создания заглушек для вас во время компиляции. Как насчет использования Microsoft FxCop, чтобы поймать любые случаи, когда вы забыли что-то добавить.

Если вы не знакомы с этим, Microsoft FxCop (также встроенный в некоторые версии Visual Studio) сканирует скомпилированные сборки и оценивает сотни правил фреймворка против вашего кода, от правильной орфографии и оболочки переменных до неиспользуемых локальных компьютеров.

Хотя я лично согласен с большинством правил, которые Microsoft вложила в FxCop, я думаю, что настоящая красота - это возможность создавать свои собственные правила. Я создал правила, которые я добавляю к FxCop, который применяет принципы CRUD, например, если у вас есть метод CreateXxx, у вас должен быть метод DeleteXxx и т. Д. Итак, если вы идентифицируете класс, который соответствует желаемому шаблону, вы можете получить список всех переменных {A, B, C}, а затем гарантировать существование FuncAB (A, B) и что FuncAC (A, C) существует и т. д.

Тогда даже младший разработчик будет обнаружен FxCop следующим время он реализует IBiVariableFunction и забывает о функции на паре.

Cheers, Adrian

+0

Спасибо за ответ. Я никогда не рассматривал использование FxCop в предложенном порядке, но мой вопрос заключается в том, что вам не нужно вручную генерировать кучу кода, чем после факта, и FxCop говорит мне, что «вы этого не сделали». Что касается сложности вопроса. «Простая» версия и пример №1 идентичны - они отличаются только использованием частичных классов для распространения кода по отдельным файлам.В двух других примерах используется/злоупотребление простым наследованием для достижения желаемого результата, а не то, что я считаю нужным подробно объяснять. –

+0

Интересно, я просто пересмотрел ваши образцы и сломал одно из моих первоначальных предположений. Я изначально думал, что функции транзитивны по их аргументам. Это FuncAB (...) и FuncBA (...) были бы одинаковыми (например, добавление вместо конкатенации), теперь я вижу, что это не так. Итак, не догадавшись ответа, поможет ли общий интерфейс? Что-то вроде IFunc , который требует наличия Func (T, U) и Func (U, T)? Вероятно, получилось довольно уродливым с большим количеством интерфейсов, объявленных ... – Adrian

+0

Я не уверен, что общий интерфейс мне подойдет, но сейчас я игнорирую проблему. –

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