Я думаю, что много беспорядка сгенерировано, не передав то, что предназначено [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
Один из подходов - использовать методы расширения с интерфейсом для обеспечения реализации вашего «производного класса», во многом как 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();
У вас есть два варианта; использовать интерфейсы или использовать композицию. Честно говоря, интерфейсы очень мощные, и после прочтения этой строки
решение интерфейса не имеет для меня никакого смысла. (Если честно, интерфейсы никогда не имели для меня особого смысла ...)
Я думаю, вам следует научиться правильно ими пользоваться. Тем не менее, если есть просто некоторая логика, которая нужна нескольким классам, но для этих классов нет смысла наследовать от одного и того же базового класса, просто создайте класс для инкапсуляции этой логики и добавьте переменную-член этого класса в свои классы. доставляющие вам проблемы. Таким образом, все классы содержат логику, но могут быть разделены в своих иерархиях наследования. Если классы должны реализовывать общий интерфейс (ы), используйте интерфейсы.
Я смотрю на это, а 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
).
Похоже, вам придется прибегнуть к интерфейсам и композиции объектов.