Что некоторые хорошие альтернативы ко множественному наследованию в.NET?

Я думаю, что много беспорядка сгенерировано, не передав то, что предназначено [1 111] переданный ссылкой . Когда некоторые люди говорят передача ссылкой , они обычно имеют в виду не сам аргумент, а скорее объект, ссылаемый . Некоторый другой говорит, что передача ссылочными средствами, что объект не может быть изменен в вызываемом. Пример:

struct Object {
    int i;
};

void sample(Object* o) { // 1
    o->i++;
}

void sample(Object const& o) { // 2
    // nothing useful here :)
}

void sample(Object & o) { // 3
    o.i++;
}

void sample1(Object o) { // 4
    o.i++;
}

int main() {
    Object obj = { 10 };
    Object const obj_c = { 10 };

    sample(&obj); // calls 1
    sample(obj) // calls 3
    sample(obj_c); // calls 2
    sample1(obj); // calls 4
}

Некоторые люди утверждали бы, что 1 и 3 передача ссылкой, в то время как 2 была бы передача значением. Другая группа людей говорит, что все кроме последнего - передача ссылкой, потому что сам объект не копируется.

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

    sample(&obj);
       // yields a `Object*`. Passes a *pointer* to the object by value. 
       // The caller can change the pointer (the parameter), but that 
       // won't change the temporary pointer created on the call side (the argument). 

    sample(obj)
       // passes the object by *reference*. It denotes the object itself. The callee
       // has got a reference parameter.

    sample(obj_c);
       // also passes *by reference*. the reference parameter references the
       // same object like the argument expression. 

    sample1(obj);
       // pass by value. The parameter object denotes a different object than the 
       // one passed in.

я голосую за следующее определение:

аргумент (1.3.1) передается ссылкой, если и только если соответствующий параметр функции, которой это называют, имеет ссылочный тип и , параметр ссылки связывает непосредственно с выражением (8.5.3/4) аргумента. Во всех других случаях мы имеем отношение к передаче значением.

, Который означает, что следующее является передачей значением:

void f1(Object const& o);
f1(Object()); // 1

void f2(int const& i);
f2(42); // 2

void f3(Object o);
f3(Object());     // 3
Object o1; f3(o1); // 4

void f4(Object *o);
Object o1; f4(&o1); // 5

1 передача значением, потому что это непосредственно не связывается. Реализация может скопировать временный файл и затем связать тот временный файл со ссылкой. 2 передача значением, потому что реализация инициализирует временный файл литерала и затем связывает со ссылкой. 3 передача значением, потому что параметр не имеет ссылочного типа. 4 передача значением по той же причине. 5 передача значением, потому что параметр не получил ссылочный тип. Следующие случаи являются передачей ссылкой (по правилам 8.5.3/4 и других):

void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1

void f2(Object const& op);
Object b; f2(b); // 2

struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference

36
задан Giffyguy 21 August 2009 в 04:10
поделиться

4 ответа

Один из подходов - использовать методы расширения с интерфейсом для обеспечения реализации вашего «производного класса», во многом как System.Linq.Queryable:

interface ICustomizableObject
{
    string SomeProperty { get; }
}

public static class CustomizableObject
{
    public static string GetXamlHeader(this ICustomizableObject obj)
    {
        return DoSomethingWith(obj.SomeProperty);
    }

    // etc
}

public class CustomizableControl : System.Windows.Controls.UserControl, ICustomizableObject
{
    public string SomeProperty { get { return "Whatever"; } }
}

Использование: Пока у вас есть директива using для (или находится в том же пространстве имен) пространства имен, в котором определены ваши методы расширения:

var cc = new CustomizableControl();
var header = cc.GetXamlHeader();
17
ответ дан 27 November 2019 в 05:59
поделиться

У вас есть два варианта; использовать интерфейсы или использовать композицию. Честно говоря, интерфейсы очень мощные, и после прочтения этой строки

решение интерфейса не имеет для меня никакого смысла. (Если честно, интерфейсы никогда не имели для меня особого смысла ...)

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

29
ответ дан 27 November 2019 в 05:59
поделиться

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

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

 ____________________________________      _____________________________________
| ICustomizable                      |    | System.Windows.Controls.UserControl |
|                                    |    |_____________________________________|
|   Func<string> XAMLHeader;         |                        ▲
|   Func<string> XAMLFooter          |◄--┐                    |
|   ICustomizabl LoadObject() |   \                    |
|   <Possible other implementations> |    \                   |
|____________________________________|     \                  |
         ▲                      ▲           \                 |
         |                      |            \                |
         |                      |             \               |
 _________________    ______________________   \    _____________________
| SpriteAnimation |  | SpriteAnimationFrame |  └---| CustomizableControl |
|_________________|  |______________________|      |_____________________|
                                                      ▲             ▲
                                                      |             |
                                                      |             |
                                                  ________    _____________
                                                 | Sprite |  | SpriteFrame |
                                                 |________|  |_____________|

Кроме того, у вас, вероятно, есть некоторая действительно статическая логика, которая, по вашему мнению, действительно принадлежит вашему типу CustomizableObject. Но это, вероятно, неверно: вы создали тип с намерением использовать этот тип в конкретной ситуации. Например, из контекста кажется, что вы создадите эти элементы управления и анимацию и будете использовать их в Windows Form. Необходимо создать собственную форму, наследуемую от базового System.Windows.Form, и этот новый тип формы должен знать об ICustomizableObject и о том, как его использовать. Вот куда пойдет ваша статическая логика.

Это кажется немного неудобным, но это доказано, когда вы решите изменить механизмы представления. Что произойдет, если вы перенесете этот код в WPF или Silverlight? Скорее всего, им потребуется использовать ваш код реализации немного иначе, чем в Windows Forms, и вам все равно, вероятно, придется изменить свои реализации CustomizableControl. Но ваша статическая логика теперь находится точно в нужном месте.

Наконец, Метод LoadObject (), который вы используете, также выделяется для меня как не в том месте. Вы говорите, что хотите, чтобы каждый настраиваемый тип предоставлял метод, который вы можете вызвать, который знает, как загружать / создавать себя. Но это совсем другое дело. Возможно, вам понадобится еще один интерфейс с именем IConstructable и ваш тип ICustomizable реализует это ( IConstructable ).

.
7
ответ дан 27 November 2019 в 05:59
поделиться

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

1
ответ дан 27 November 2019 в 05:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: