Ricardo Altamirano
Ricardo Altamirano

Reputation: 15198

Clearing a variable after it's used in a object initializer clears the object's property too?

Why is the Tags property of Book empty after this code runs?

class Program
{
    static void Main(string[] args)
    {
        List<Book> books = new List<Book>();
        List<String> tags = new List<String> {"tag1", "tag2", "tag3"};
        String title = "a title";
        books.Add(new Book
        {
            Title = title,
            Author = "an author",
            Tags = tags
        });
        Console.WriteLine("(" + title + ")");
        Console.WriteLine((books[0]).Tags.Count());

        title = String.Empty;
        tags.Clear();

        Console.WriteLine("(" + title + ")");
        Console.WriteLine((books[0]).Tags.Count());
    }
}

The code for Book:

public class Book
{
    public String Title { get; set; }
    public String Author { get; set; }
    public List<String> Tags { get; set; }
}

Running this code outputs

("a title")
3
()
0

Are tags and title being passed by reference here? Renaming the respective properties produces the same output.

EDIT:

I just realised that I meant for every Console.WriteLine statement to refer to the object, not just the tags one. I meant this:

Book aBook = books[0];
Console.WriteLine("(" + aBook.Title + ")");
Console.WriteLine(aBook.Tags.Count());

title = String.Empty;
tags.Clear();

Console.WriteLine("(" + aBook.Title + ")");
Console.WriteLine(aBook.Tags.Count());

which as expected, outputs:

("a title")
3
("a title")
0

but since I made a mistake in my initial question, I'm leaving it as is since the parts of the answers that refer to title are referencing the original code.

Upvotes: 3

Views: 6255

Answers (3)

Reed Copsey
Reed Copsey

Reputation: 564383

Are tags and title being passed by reference here?

Yes.

However, the confusion (based on comments) appears to be due to the difference in how Tags and Title behave in your code.

The difference in behavior between Tags and Title when you do:

title = String.Empty;
tags.Clear();

Is due to the fact that, in the first case, you're assigning a completely new instance to title. When you call tags.Clear(), however, you're mutating the existing instance, which is "shared" with the Tags property within book[0] (since List<string> is a class and has reference type semantics).

Upvotes: 1

ken2k
ken2k

Reputation: 48975

The Tags property of your Book object refers to the same object instance as the list you created on your second line of code (List<String> tags = new List<String> {"tag1", "tag2", "tag3"};).

When you wrote Tags = tags, you're actually saying that Tags points to the same instance that tags.

That's why when you clear tags, Tags is cleared too as it's the same object reference.

Upvotes: 1

Oded
Oded

Reputation: 498972

List<T> is a reference type, so yes, you get reference semantics here.

You need to assign a copy of tags to the property if you want them to be independent.

Tags = new List<string>(tags);

Upvotes: 5

Related Questions