6

Maybe it's a newbie question, but could anyone explain me how the tied/linked classes (I don't know their true names) are made? The example can be LINQ TO XML.

When I have the beneath code:

XDocument doc = XDocument.Load("...");
XElement element = doc.Element("root");
element.SetAttribute("NewAttribute", "BlahBlah");
doc.Save("...");

I change only element variable (I don't need to update it in doc because its referenced). How to create such classes?

[edit]
I tried @animaonline's code and it works

A a = new A();
B b = a.B(0);
b.Name = "asd";
Console.WriteLine(a.Bs[0].Name); // output "asd"

But tell what's the difference with the code above and below?

List<string> list = new List<string>();
list.Add("test1");
list.Add("test2");
var test = list.FirstOrDefault();
test = "asdasda";
Console.WriteLine(list[0]); // output "test1" - why not "asdasda" if the above example works???
AstroCB
  • 12,337
  • 20
  • 57
  • 73
Nickon
  • 9,652
  • 12
  • 64
  • 119
  • it lools like you're lacking basic knowledge of how the .NET works. I suggest you read a tutorial on value/reference types. – animaonline Aug 01 '13 at 14:47
  • 1
    Yes, I took care of it. Now I know a little more and everything is clear to me:) Thanks for answers! – Nickon Aug 02 '13 at 06:27

3 Answers3

4

doc.Element is a method, it returns a reference to the first (in document order) child element with the specified XName.

Consider this example:

public class A
{
    public A()
    {
        this.Bs = new List<B>();

        this.Bs.Add(new B { Name = "a", Value = "aaa" });
        this.Bs.Add(new B { Name = "b", Value = "bbb" });
        this.Bs.Add(new B { Name = "c", Value = "ccc" });
    }

    public List<B> Bs { get; set; }

    public B B(int index)
    {
        if (this.Bs != null && this.Bs[index] != null)
            return this.Bs[index];

        return null;
    }
}

public class B
{
    public string Name { get; set; }
    public string Value { get; set; }
}

Usage:

A a = new A();
var refToA = a.B(0);
refToA.Value = "Some New Value";

foreach (var bs in a.Bs)
    System.Console.WriteLine(bs.Value);

Explanation:

As you can see the B() method returns a reference to a list item in the A class, updating it will change the value in the A.bs list as well, because it's the very same object.

animaonline
  • 3,715
  • 5
  • 30
  • 57
  • Yes, but how the `FirstOrDefault` method is made that it returns a reference? You return the referenced B, because you use `LINQ`. I want to find out how `LINQ` classes are made. – Nickon Aug 01 '13 at 13:16
  • It was only an example, it doesn't matter as long as it returns a reference type you will get this behaviour, there is nothing magical about LINQ. I have updated my answer.. – animaonline Aug 01 '13 at 13:17
  • 1
    Have a look at the mono implementation of FirstOrDefault https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Linq/Enumerable.cs – animaonline Aug 01 '13 at 13:43
1

I think I understand what you're asking. The validity of my response is based entirely on this premise. :D


Class members do not have to be primitive types - they can be other classes too.

Simple example

Given two classes SimpleXDocument and SimpleXElement, note that SimpleXDocument has a member / exposed property of type SimpleXElement:

public Class SimpleXDocument
{
    private SimpleXElement _element;
    public SimpleXDocument(){ this._element = null;}
    public SimpleXDocument(SimpleXElement element){this._element = element;}
    public SimpleXElement Element
    {
        get{return this._element;}
        set{this._element = value;}
    }
}

Public Class SimpleXElement
{
    private String _value;
    public SimpleXElement(){this._value = String.Empty;}
    public SimpleXElement(String value){this._value = value;}
    public String Value
    {
        get{return this._value;}
        set{this._value = value;}
    }
}

SimpleXDocument references its own member of type SimpleXElement. You can do things like:

SimpleXDocument doc = new SimpleXDocument();
doc.Element = new SimpleXElement("Test 1");
SimpleXElement element = new SimpleXElement();
element.Value = "Test 2";
doc = New SimpleXDocument(element);
SimpleXElement anotherElement = new SimpleXElement("another test");
doc.Element = anotherElement;
doc.Element.Value = "yet another test";
anotherElement.Value = "final test"; //N.B. this will update doc.Element.Value too!
Tom Tom
  • 423
  • 4
  • 9
  • Consider my example. The XDocument is being loaded from file and it returns an element. Then if I change something in this element, it affects in XDocument object. Now when I save XDocument, the changes on element will be saved aswell. – Nickon Aug 01 '13 at 13:21
  • Yes, I'm aware of this. My deliberately simplified example would exhibit the same behaviour. The XDocument in your example contains (at least one) XElement member _somewhere_ in the class definition - this is all created / instantiated by the .Load() method. The object you 'extract' through doc.Element("...") references the same chunk of memory where the XElement created on Load() is stored - they are one and the same, hence changes to 'one' affects the 'other'. – Tom Tom Aug 01 '13 at 13:53
-2

As I understand u need not a reference to element but a copy of an object which stands behind the reference.

I think this answer will help u: https://stackoverflow.com/a/129395/1360411

Community
  • 1
  • 1
sickUnit
  • 319
  • 2
  • 5