Type of Type

  • Thread starter Thread starter marc
  • Start date Start date
M

marc

Hoi there,

I am a Delphi Programer who moved over to C# some months ago. So far I
am really happy with C# and feelt myself confortable quite fast. Just
some advanced questions regarding the type system are left.

One question is the "type of type" issue:

In Delphi (Pascal) I was able to do the following (free translation to
C# pseudocode ;-) ):

// A simple class
public class MyChildPageBase
{
}

// A simple derived class
public class MyChildTasks : MyChildPageBase
{
}

// A specified type of the base class
public type of MyChildPageBaseclass MyChildPageBaseType;


Instead using Type I then could use this new type like this:

public void CreateChildPage(MyChildPageBaseType childType)
{
ChildBase child = new childType.CreateInstance();
}

This way the compiler ensured that CreateChildPage() could only be
called with the type of MyChildPageBase or any derived class. Look at
this:

CreateChildPage(MyChildTasks); // <- works well
CreateChildPage(MyChildPageBase); // <- works well
CreateChildPage(int); // <- compiler error

I think I can use the IS operator in C# to ensure types at runtime but
I'd like to check it at compile-time so I already get compiler-error
for the last line of the above code.

Does anybody have an idea if and how I can do this in C#?

Cheers,
Marc
 
Well, if I understand what you are doing, then in 2.0 generics may be the
answer:

public void CreateChildPage<T>() where T : MyChildPageBase, new()
{
T child = new T();
// whatever else, perhaps returning child with the sig. "public T
Create..."
}

Then call CreateChildPage<MyChildTasks>() or
CreateChildPage<MyChildPageBase>() will be fine, but CreateChildPage<int>()
will fail at compile time.

Is this what you mean?

Marc
 
public void CreateChildPage(Type type)
{
// now you can use IS
if(type is MyChildTasks)
return new type.CreateInstance();

if(type is MyChildPageBase)
return new type.CreateInstance();

throw new Exception(...);
}


However, I think it would be better to have it as you did. As a
programmer, I would rather know at compile time if I'm passing an
incorrect type vs. finding out at runtime that I goofed.
 
Turn on compiler warnings ;-p

The variable "type" is declared as a "Type", so can never be (inherit from)
either MyChildTasks or MyChildPageBase, so "is" is not the right test here;
to replace your "is" tests you would need one of (depending on exact
behaviour wanted):

if(type == typeof(MyChildTasks)) // strict match
OR
if(type.IsAssignableFrom(typeof(MyChildTasks))) // exact or subclass
OR
if(type.IsSubclassOf(typeof(MyChildTasks))) // strict subclass

The actual creation would look like:
type.GetConstructor(Type.EmptyTypes).Invoke(null);
Did you mean "new {concrete class}"? Note the above usage also removes the
need for the tests in the first place, but only validates at runtime.

All very messy, eh? However, in 2.0 generics is a much better solution. See
previous post.

Marc
 
Jeff said:
public void CreateChildPage(Type type)
{
// now you can use IS
if(type is MyChildTasks)
return new type.CreateInstance();

if(type is MyChildPageBase)
return new type.CreateInstance();

throw new Exception(...);
}


However, I think it would be better to have it as you did. As a
programmer, I would rather know at compile time if I'm passing an
incorrect type vs. finding out at runtime that I goofed.

Hi Jeff,
if(type is MyChildTasks)

I'm afraid that won't work. You need to do this:

///
if ( type == typeof( MyChildTasks ) )
///

The reason being, 'is' tests that the instance of an object is of the given
type, the instance of 'type' will always be a System.Type, never
a 'MyChildTasks'.

Also, your method returns void, so your return statements are invalid.

You'd need to rewrite your method to something like this:

///
MyChildPageBase CreateChildPage ( Type type )
{
if ( type == typeof( MyChildTasks ) )
return new MyChildTasks();
else if ( type == typeof( MyChildPageBase ) )
return new MyChildPageBase();

throw new Exception( "Given type is invalid" );
}
///
 
One question is the "type of type" issue:

I think you're talking about Delphi metaclasses, i.e.:

type
TMyClass = class of TMyObject;

The closest analogue is Type, and the create you're looking for could
either be Activator.Create(Type) or (if you need fine control)
Type.GetConstructor() followed by ConstructorInfo.Invoke().
I think I can use the IS operator in C# to ensure types at runtime but
I'd like to check it at compile-time so I already get compiler-error
for the last line of the above code.

Does anybody have an idea if and how I can do this in C#?

There is no exact equivalent, which would be type variable which is also
bounded (i.e. restricted to a particular class and all its descendants)
and statically type-checked as such.

-- Barry
 
hey guys, thanks a lot for all thouse fast replies!!! i am impressed!
I think you're talking about Delphi metaclasses, i.e.:

type
TMyClass = class of TMyObject;

yes, exactly. maybe its better if i write some more pascal-sample in
here es there seems to be other pascal-experts around there ;-)

the pascal-pattern i try to get into c# is the following:

type

TMyObj1 = class
end;

TMyObj2 = class (TMyObj1)
end;

TMyObj1Class = class of TMyObj1;

function DoSomething(var myObj: TMyObj1; myObjClass: TMyObj1Class):
boolean;
begin
if not assigned(myObj) then begin
myObj := myObjClass.Create();
end;
end;

Now use this function/method like this:

var
myObj1: TMyObj1;
myObj2: TMyObj2;
begin
DoSomething(myObj1); // compiles well
DoSomething(myObj2); // compiles well
DoSomething(integer); // compiler error !!
DoSomething(string); // compiler errer !!

hope i will not be kicked here because of the pascal instead of c#
;-))))

using IF-statements will work at runtime, yet but not at compile-time.
i d' like to know at compile-time where i (or any other developer ;-) )
- used the wrong types so i have to run all the code to get exceptions.

from my point of view the generic sample is the one getting closest as
then the compiler will do the type-checks. but i am having problems
gettings this to compile as i get a tricky compiler-error:

"Cannot convert type 'ChildTask to 'ChildBase' "

it seems i got something wrong. hmm... have to "investigate" a little
more ;-)

cheers,
marc
 
<[email protected]> a écrit dans le message de (e-mail address removed)...

| I am a Delphi Programer who moved over to C# some months ago. So far I
| am really happy with C# and feelt myself confortable quite fast. Just
| some advanced questions regarding the type system are left.
|
| One question is the "type of type" issue:
|
| In Delphi (Pascal) I was able to do the following (free translation to
| C# pseudocode ;-) ):
|
| // A simple class
| public class MyChildPageBase
| {
| }
|
| // A simple derived class
| public class MyChildTasks : MyChildPageBase
| {
| }
|
| // A specified type of the base class
| public type of MyChildPageBaseclass MyChildPageBaseType;
|
|
| Instead using Type I then could use this new type like this:
|
| public void CreateChildPage(MyChildPageBaseType childType)
| {
| ChildBase child = new childType.CreateInstance();
| }
|
| This way the compiler ensured that CreateChildPage() could only be
| called with the type of MyChildPageBase or any derived class. Look at
| this:
|
| CreateChildPage(MyChildTasks); // <- works well
| CreateChildPage(MyChildPageBase); // <- works well
| CreateChildPage(int); // <- compiler error
|
| I think I can use the IS operator in C# to ensure types at runtime but
| I'd like to check it at compile-time so I already get compiler-error
| for the last line of the above code.

If you are using C# 1.1, then the only way to do this is to create your own
"metaclass" with a Create method that returns instances of the correct type.

I wrote an article for the UK Developers Group on this subject

http://www.prototypical.co.uk/pdf/C# virtual delphi.pdf

As Marc says, if you are using C# 2.0, then generics are your friend.

Joanna
 
Barry said:
There is no exact equivalent, which would be type variable which is also
bounded (i.e. restricted to a particular class and all its descendants)
and statically type-checked as such.

didn't get this one. what do you mean by this?

thx, marc
 
didn't get this one. what do you mean by this?

A Delphi metaclass is a type which refers to a type. So is .NET's
System.Type. The difference with Delphi metaclasses is that they can be
bounded - i.e. limited in a certain way.

The metaclass "TClass" can refer to any Delphi type descending from
TObject, or TObject itself. "TComponentClass" can only refer to types
descending from TComponent, or TComponent itself - it is bounded, or
restricted to a particular class (TComponent) and all its descendants
(TControl, etc...).

There is no exact equivalent in C# or .NET, and it isn't possible to
write a statically checked version in C# 2.0 - i.e. one that caused a
compile-time error when you try to assign the wrong type into the
variable. For example, you'll get a compile-time error in Delphi if you
try to assign TStringList into a variable of type TComponentClass. This
is not possible right now with C#.

(As a side note: if C# ever exposes the variance capabilities of the
underlying CLI, it would actually be possible to do something fairly
close to this using generics. As it is, I can think of a couple of ways
of hacking something up in IL, but it would be a pain to maintain.)

-- Barry
 
Back
Top