tags:

views:

293

answers:

9

I was working in the Microsoft.Ink dll recently using C# and was debugging a problem (which is not related to this) I noticed, that when I was debugging it, ink objects had a strokes object, which had an ink object, which had.... etc.

This confused me, as I was under the assumption you could not do this (I come from a C++ Background)

But I ignored it, solved the problem, and moved on. Today, I run into a similar problem, as I look at a class which had a private member which was the same class as itself.

public sealed class Factory
{

    private static Factory instance = new Factory();
}

How is that even possible? I can now call instance.instance.instance.instance...etc. This, as you can imagine, hurts my mortal brain, and I'm sure it can't be good on the computer either. How does the compiler deal with this? And Just how deep does the rabbit hole go?

+5  A: 

it's not necessarily recursive by nature. think of a linked list. or a tree.

class Directory
{
   string name;
   Directory parentDirectory;
}

It's just allows objects of that class to have an internal reference to another object of that class.

Tim Hoolihan
+6  A: 

This is a software pattern known as "Singleton".

Some people frown upon the use of the pattern for more reasons than just stated in the question but for better or for worse it is a common pattern in the .NET Framework. You will find Singleton Properties (or fields) on classes that are meant to be instantiated only once. Think of a static Instance property as a global hook upon which to hang an object.

Ray Vernagus
Actually, its not a singleton. The instance isn't public and there isn't a private default constructor.
Will
@Will, yea, it looks like part of the singleton. If there was a public property for instance, then it would be a singleton.
phsr
My answer was pointing this out, then I saw everyone else jumped on it as well.
Robin Robinson
Singleton properties don't necessarily have to be public. It's just a way to restrict a class to a single instance. Naming a property "Instance" is usually a clue that it's to be used as a Singleton.
Ray Vernagus
No, he's _not_ totally right, divo. I was, also, going to write the same. I didn't because, although it has the appearance of being slightly singleton-y, the code he provides is NOT a singleton for the reasons I pointed out above (no private default constructor and no public property). The code provided isn't a singleton, and the description of the code Kurisu provided says nothing about a public property for this private static field.
Will
+4  A: 

Since this is a class, and not a struct, when you declare a field that is the class, you are in actuality only defining a reference to a class. This allows you to keep having references, privded you assign them.

In your case, you're reference allocates a new class, but it is static, so it's only going to do it one time, no matter how many classes you create. The instance constructor runs the first time Factory is used, and will call a single non-static constructor. Doing instance.instance.instance is not allowed, since instance is static. You cannot access a static variable from a member - you need to do Factory.instance.

However, you ~could~ make instance non-static, and have it be a reference to some other "Factory" class, or even a reference to this. In that case, you could chain instance.instance.instance - but it will just follow the references as long as you've set them. Everything works, no problems.

Reed Copsey
Technically doing Factory.instance.instance.instance should be flagged as an error or warning because you're accessing a static member as if it were a non-static member. I know in java this produces a warning.
Jherico
Very true. Editting to correct.
Reed Copsey
+1 for mentioning that this is not working on structs as these are value types.
0xA3
+2  A: 

Because it's static and therefore there is only one copy of the variable instance within the AppDomain.

What you're thinking of is this:

public class Foo
{
  private Foo lol = new Foo();
}

Notice, everything here is instance, not static.

Will
In the instance example, it "goes down the rabbit hole" deep enough to cause a StackOverflowException to be thrown...
Greg
In your sample you would obviously get a SO exception. However, whether "Declaring a Class as a Member of itself" makes sense is not a matter of static versus instance. See the example in my answer.
0xA3
+1  A: 

I think you should ask the other way around: Why shouldn't this be possible? Factory is just a type like any type which gets resolved by the compiler.

As most of the answers here point out that this is working only because Factory is a static field, I have added the following sample. Please note that this is a very primitive sample of a chained list (you probably wouldn't implement it that way for various reasons, but I didn't come up with a better example yet). In this example, ChainedListItem is a container for an element of a single-linked list, which contains a field of the very same type to point to the next item in the list. The list has an (empty) head element and the last element is marked by having an empty _nextItem field:

public class ChainedListItem<T>
{
    private ChainedListItem<T> _nextItem;
    T _content;

    public ChainedListItem<T> NextItem
    {
        get { return _nextItem; }
        set { _nextItem = value; }
    }

    public T Content
    {
        get { return _content; }
        set { _content = value; }
    }

    public ChainedListItem<T> Add(T content)
    {
        _nextItem = new ChainedListItem<T>();
        _nextItem.Content = content;
        return _nextItem;
    }

    public void Dump()
    {
        ChainedListItem<T> current = this;
        while ((current = current.NextItem) != null)
        {
            Console.WriteLine(current._content);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        ChainedListItem<int> chainedList = new ChainedListItem<int>();
        chainedList.Add(1).Add(2).Add(3);
        chainedList.Dump();        
    }
}

The "rabbit hole" goes as deep as your stack space allows you to make another call to the constructor of the type. If you try to go deeper than that, you will get a stackoverflow exception as with any other recursion.

By the way, the code that you wrote in your answer is showing a very basic implementation of a Singleton which is actually based on having a (private) static member of the same type as the surrounding type.

And, last but not least, such constructs are also perfectly fine in C++.

0xA3
A: 

This is done all the time is most OO languages. instance is a static member of Factory. There is nothing unusual about this code. It is standard Factory pattern. Do you also have a problem with code like this?

x = x + 1;
jmucchiello
rude and quite unhelpful.
GuiSim
And "it is standard for the Factory pattern" is also incorrect. You should revise or delete your answer. -1
0xA3
Rude? Short perhaps. But I was not being rude. The question is meant to direct the OP to consider other places in computing where "logic" does not always apply.
jmucchiello
+2  A: 

There will only ever be one instance of 'instance' because it is static. The only way you should be able to access it is by calling Factory.instance.

string text = Factory.instance.ToString(); // legal
string text2 = Factory.instance.instance.ToString(); // compiler error
John JJ Curtis
A: 

It is a singleton. Meaning there is really only one instance of the class.

Is that the entire class? Typically in C# you will see a singleton like

public class SomeClass
{

  static readonly SomeClass instance = new SomeClass();


     public static SomeClass Instance
     {
      get { return instance; }
     } 


     static SomeClass() 
     {
     }

     SomeClass()
     {
     }
}
David Basarab
A: 

I'm not sure how you would even access the instance since it is private. The only thing this would be useful for is a Singleton implementation, but if that is the case you are mission the public property exposing the instance.

Robin Robinson