Question about Class Methods

  • Thread starter Magnus.Moraberg
  • Start date
M

Magnus.Moraberg

Hi,

Lets say I have a class called Point and I give this class the
following properties -

int[] CoordinatesInPixels{...}
float[] CoordinatesInInches{...}

And the Method -

bool IsInFirstQuadrant(){...}

My question is, if I create two objects of this class, do I have two
instances for each of the two properties and two instances of the
IsInFirstQuadrant() method stored in memory. That is, does all the
code need to execute IsInFirstQuadrant get loaded into memory twice,
or is the address of point1.IsInFirstQuadrant() equal to that of
point2.IsInFirstQuadrant().

Thanks for your help,

Barry.
 
M

Marc Gravell

Methods are only loaded once (assuming a single AppDomain etc).
Properties are actually just named methods too - the only thing that
takes space per instance is the object header itself, and any fields
(instance variables for the type). Since arrays are reference-types,
each instance will require space for the 2 references. Assuming the
array data is separate per instance, then each instance will also have a
corresponding block of data on the manged heap for each array itself.

Marc
 
M

Michael C

My question is, if I create two objects of this class, do I have two
instances for each of the two properties and two instances of the
IsInFirstQuadrant() method stored in memory. That is, does all the
code need to execute IsInFirstQuadrant get loaded into memory twice,

In addition to marc's response, the way it works is quite interesting. There
is only ever one function created no matter how many objects exist in
memory. So how can that one function work when there are multiple instances
of your class? Simple, a pointer to your class is passed into that function,
eg If you have this

class MyClass
{
public void DoIt()
{
}
}

Then a single function is defined that looks like this:

void DoIt(MyClass* this)
{
}

the DoIt function knows which module level variables to use by the 'this'
pointer. That way 1 function can work accross thousands of instances of your
class.

Disclaimer: To be honest I don't know the internal working of dot net too
well but this is how it works in other languages so I'd be suprised if it
was vastly different here. I'm sure Peter Dunnydore will chime in if it is.
There may even be other additional hidden parameters. It's pretty much the
same as non oop code where you would get a handle to an object, eg

int handle = CreateThingy();
ThingyDoSomething(handle, 1, 2, 3, 4);

dot net just wraps it all up nicely for you to create the concept of an
object:

Thingy t = new Thingy();
t.DoSomething(1, 2, 3, 4);

Michael
 
M

Marc Gravell

so I'd be suprised if it was vastly different here.

It is, indeed, the same in .NET (and C# in particular). The only
subtlety is that the "this" parameter is not named, with the compiler
just using the "ldarg.0" op-code in place of "this" in the body.

With C# 3 you can replicate a similar setup with "extension methods",
except the arg *is* named, and there is no virtcall involved (with the
interesting side-effect that you can call "instance" extension methods
on null instances).

Marc
 
J

Jon Skeet [C# MVP]

 > so I'd be suprised if it was vastly different here.

It is, indeed, the same in .NET (and C# in particular). The only
subtlety is that the "this" parameter is not named, with the compiler
just using the "ldarg.0" op-code in place of "this" in the body.

One more subtlety: for value types, the implicit "this" parameter is
passed by reference. Most of the time this isn't important (as value
types should almost always be immutable) but it matters when you're
trying to create an open delegate...

Jon
 
M

Michael C

Jon Skeet said:
One more subtlety: for value types, the implicit "this" parameter is
passed by reference. Most of the time this isn't important (as value
t>ypes should almost always be immutable) but it matters when you're
trying to create an open delegate...

Can you elaborate on that?

Jon
 
P

Pavel Minaev

Michael C said:
t>ypes should almost always be immutable) but it matters when you're

Can you elaborate on that?

It means that when you write something like this:

struct Foo
{
int x, y;
void Bar() { ... }
}

the actual signature of the method in runtime is more like:

static void Bar(ref Foo this);

which is why you can change values of struct fields in your methods, and
they persist. But it has some other interesting side effects. For example,
given this:

void Swap<T>(ref T x, ref T y);

you could write Foo.Bar like this:

void Bar()
{
Foo other;
...
Swap(ref this, other);
}

and it also allows for the following puzzling syntax in constructors and
methods:

Foo()
{
this = new Foo(1, 2);
}
 
J

Jon Skeet [C# MVP]

and it also allows for the following puzzling syntax in constructors and
methods:

  Foo()
  {
    this = new Foo(1, 2);
  }

Except that you can't define your own parameterless constructor for a
struct ;)

The point about open delegates is best shown with some code. Note how
the delegate type I use for the class has a by-value first parameter
whereas the one for the struct has a by-ref first parameter.

using System;
using System.Reflection;

struct ValueType
{
readonly string name;

public ValueType(string name)
{
this.name = name;
}

public void Foo(int x)
{
Console.WriteLine("{0}: {1}", name, x);
}
}

class RefType
{
readonly string name;

public RefType(string name)
{
this.name = name;
}

public void Foo(int x)
{
Console.WriteLine("{0}: {1}", name, x);
}
}

delegate void ValueFoo(ref ValueType v, int i);
delegate void RefFoo(RefType v, int i);

class Test
{
static void Main()
{
MethodInfo valueInfo = typeof(ValueType).GetMethod("Foo");
MethodInfo refInfo = typeof(RefType).GetMethod("Foo");

ValueFoo valueDel = (ValueFoo) Delegate.CreateDelegate
(typeof(ValueFoo), valueInfo);

RefFoo refDel = (RefFoo) Delegate.CreateDelegate
(typeof(RefFoo), refInfo);

ValueType vt = new ValueType("val");
RefType rt = new RefType("ref");

valueDel(ref vt, 10);
refDel(rt, 20);
}
}

Jon
 
M

Marc Gravell

Can you elaborate on that?

An open delegate is where we get the runtime to treat the "this"
argument as simply the first argument, as though it were a static
method. The problem is that the delegate still needs to meet the
declared signature. So with a reference-type (class):

public class X {
public void Y() {...}
}

You can get an open Action<X> delegate to Y(), and pass in the X at
runtime:

Action<X> action = ...
Y y = ...
action(y);

However, with a value-type, the open-delegate can't use Action<X>,
since this doesn't have "ref" on the first argument (you get a bind
failure); you need to use a delegate that uses "ref" on the first
argument. A full example is below.

Marc

using System;
struct Foo
{
private readonly int bar;
public int Bar { get { return bar; } }
public Foo(int bar)
{
this.bar = bar;
}
public void Test()
{
this = new Foo(Bar + 1);
}
}
delegate void RefAction<T>(ref T foo);
static class Program
{
static void Main()
{
Foo foo = new Foo(1);
Console.WriteLine("Init: {0}", foo.Bar);
foo.Test();
Console.WriteLine("After Test: {0}", foo.Bar);

RefAction<Foo> openDelegate =
(RefAction<Foo>)Delegate.CreateDelegate(
typeof(RefAction<Foo>),
typeof(Foo).GetMethod("Test"));

openDelegate(ref foo);
Console.WriteLine("After Delegate Invoke: {0}", foo.Bar);
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top