Simple Syntax question (i think)

B

Ben Daniel

Basically what I want to know is how to return a class type (not an
instantiation of a class but a class itself).

For (a trivial) example, let's say I have a base class Animal and
derived classes Dog, Cat & Mouse. I want a function that I can pass a
food type as a string and get back the class of Animal that eats that
food (not an instance of the class but the class itself).

I've had trouble figuring out how to write this in cs. Here is what it
would look like in delphi:
(all types start with T in delphi)

TAnimal = class;
TAnimalClass = class of TAnimal;
TMouse = class(Animal);
TCat = class(TAnimal);
TDog = class(TAnimal);

function GetAnimalThatEats(food: string): TAnimalClass;
begin
if food = 'cheese' then
result := TMouse
else if food = 'fish' then
result := TCat
else if food = 'shoes' then
result := TDog
else
raise exception.Create('no registered animal that eats food type:
' + food);
end;

procedure Test();
var
PetClass: TAnimalClass;
Pet: TAnimal;
begin
PetClass := GetAnimalThatEats('fish'); // Get the class
Pet := PetClass.Create; // Create a new object from that class (will
create a cat)
end;

Could someone tell me the equivalent syntax in c# please?
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Ben said:
Basically what I want to know is how to return a class type (not an
instantiation of a class but a class itself).

For (a trivial) example, let's say I have a base class Animal and
derived classes Dog, Cat & Mouse. I want a function that I can pass a
food type as a string and get back the class of Animal that eats that
food (not an instance of the class but the class itself).

I've had trouble figuring out how to write this in cs. Here is what it
would look like in delphi:
(all types start with T in delphi)

TAnimal = class;
TAnimalClass = class of TAnimal;
TMouse = class(Animal);
TCat = class(TAnimal);
TDog = class(TAnimal);

function GetAnimalThatEats(food: string): TAnimalClass;
begin
if food = 'cheese' then
result := TMouse
else if food = 'fish' then
result := TCat
else if food = 'shoes' then
result := TDog
else
raise exception.Create('no registered animal that eats food type:
' + food);
end;

procedure Test();
var
PetClass: TAnimalClass;
Pet: TAnimal;
begin
PetClass := GetAnimalThatEats('fish'); // Get the class
Pet := PetClass.Create; // Create a new object from that class (will
create a cat)
end;

Could someone tell me the equivalent syntax in c# please?

Return a Type object:

public Type GetAnimalThatEats(string food) {
switch (food) {
case "cheese": return typeof(Mouse);
case "fish": return typeof(Cat);
case "shoes": return typeof(Dog);
default: throw new ApplicationException("No registered animal
east food of type '" + food + "'.");
}
}
 
B

Ben Daniel

This example in c# is ALMOST what I want but I don't want to have to
instantiate the relevant class in my GetAnimalThatEats function -
please help!

using System;
using System.Collections.Generic;

public class Animal
{
}

public class Mouse : Animal
{
}

public class Cat : Animal
{
}

public class Dog : Animal
{
}

public class Test
{
public static void Main()
{
// get the class of animal that eats fish (should be cat)
Type animal = GetAnimalThatEats("fish");
Console.WriteLine(animal.FullName);
Console.ReadLine();
}

public static Type GetAnimalThatEats(string food)
{
Animal animal;
if (food == "cheese")
animal = new Mouse();
else if (food == "fish")
animal = new Cat();
else if (food == "shoes")
animal = new Dog();
else
throw new Exception("no registered animal that eats food type: "
+ food);
return animal.GetType();
}
}
 
B

Barry Kelly

Ben said:
Basically what I want to know is how to return a class type (not an
instantiation of a class but a class itself).

An exact analog to the Delphi concept, a metaclass, doesn't exist. You
can use a Type instance instead - e.g. typeof(TAnimal), and later
construct it with e.g. Activator.CreateInstance(Type).

-- Barry
 
B

Ben Daniel

public Type GetAnimalThatEats(string food) {
switch (food) {
case "cheese": return typeof(Mouse);
case "fish": return typeof(Cat);
case "shoes": return typeof(Dog);
default: throw new ApplicationException("No registered animal
east food of type '" + food + "'.");

Sweet, thanks Göran. That's exactly what I wanted. Cheers!
 
B

Ben Daniel

Thanks Barry + Goran,

Hey another question: once you've got the type back from GetAnimal,
let's say you don't want to create an instance of the animal type yet,
you just want to call a static method of the animal class. This static
method might be overridden in the derived animal types like Mouse,
Cat, Dog, etc.

e.g.
public abstract class Animal
{
public static abstract string Says();
}

public class Cat : Animal
{
public static override string Says()
{
return "meow";
}
}

Type animalType = GetAnimalThatEats("fish");
Console.WriteLine(animalType.Says()); // <-- would this work?
 
B

Ben Daniel

Oh doh, just one more question:

Once you've got the type from the GetAnimalThatEats function, let's
say you don't actually want to instaniate the type yet but want to
call a static method of the class?
 
J

Jon Skeet [C# MVP]

Oh doh, just one more question:

Once you've got the type from the GetAnimalThatEats function, let's
say you don't actually want to instaniate the type yet but want to
call a static method of the class?

You'd have to use reflection to do that (Type.GetMethod etc). Static
methods can't be part of interfaces etc, so there's no way (in the
language itself) of saying "I know that this is a type which has a
particular static method, now call it".

Jon
 
B

Barry Kelly

Ben said:
Thanks Barry + Goran,

Hey another question: once you've got the type back from GetAnimal,
let's say you don't want to create an instance of the animal type yet,
you just want to call a static method of the animal class. This static
method might be overridden in the derived animal types like Mouse,
Cat, Dog, etc.

Like John says, you have to use Type.GetMethod, or perhaps use
attributes to declaratively add the information you want to the types.

Check out the Factory Pattern. The Factory Pattern is common in
languages like C# and Java that don't support metaclasses. Basically, a
Delphi metaclass is like a built-in Factory Pattern. To get the same
behaviour in C# and Java, you need to do it yourself.

-- Barry
 

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