I think you're wondering how many copies of the Cache
object will get created. You only want one copy to be shared by multiple client objects. Well, there's a very simple rule you can remember in C#, whenever you want to know how many separate copies of your object will be created.
If the object's type is declared with
the class
keyword, then there is
only one way to make a new instance of
it: with the new
keyword.
There are minor exceptions to this: you can call BCL methods that create objects, but the point is that it is explicit. You have to specifically ask for it to happen. The language will not automatically make copies of class
objects.
So in your example, you have a class
called Cache
, and so you know for certain that you can pass around variables of type Cache
as much as you like, and no further copies of Cache
will be created. All the variables that have that object assigned to them will be "pointing" to the same original object. This is because a Cache
variable doesn't store the object itself, but only the location of a Cache
object in memory.
Contrast this with what happens if you declare a struct
type instead of a class
. Now when you declare a variable of that type, the variable itself has to be large enough to store all the data declared in the struct
. Every variable is a separate copy. Every parameter is a separate copy.
You can override this by adding the ref
keyword, but it's a pretty unusual keyword in most programs. The out
keyword is more common, and is best thought of as a way to give a method more than one return value.
What effect does ref
have on a variable if it is of class
type? In your example:
public ObjectLoader(Cache cache) {
// do stuff with cache (store it?)
}
I could construct two object loaders like this:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(c),
ObjectLoader b = new ObjectLoader(c);
How many objects did we just create? Simply count the new
keywords. Now, suppose we added the ref
keyword:
public ObjectLoader(ref Cache cache) {
_cache = cache; // store
// do something very odd!
cache = new Cache();
}
Hidden inside that constructor, I've created another cache, and stored it in the parameter I was passed. Because it's a ref
parameter, I've affected the caller's variable! So in the calling code:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(ref c),
ObjectLoader b = new ObjectLoader(ref c);
Now we have five uses of new
: three in the above snippet, plus two calls to the modified ObjectLoader
constructor. Each time ObjectLoader
's constructor is called, we pass it c
. We have to put the ref
keyword, which is a very good thing because it lets the person reading the code know that something strange is going on. The variable c
points to a different Cache
after ObjectLoader
's constructor returns. So b
's ObjectLoader
ends up storing a pointer to a different Cache
to a
!
Needless to say, this would be quite a messy pattern for the code to have. It would be even worse if we didn't have to put the ref
keyword at the calling site!