Reputation: 36058
I have:
class Person
{
public Person(string name, int age)
{
this.Name = name;
}
public string Name { get; set; }
public virtual void Speak()
{
Console.Write("Hello I am a person");
}
public static T GenerateRandomInstance<T>() where T: Person
{
var p = new T("hello", 4); // error does not compile
// rondomize properties
return p;
}
}
class Student : Person
{
// constructor I call the base class here
public Student(string name, int age)
: base(name, age)
{
}
public override void Speak()
{
Console.Write("Hello I am a student");
}
}
The problem that I have is that when I do:
Student.GenerateRandomInstance();
I get a Person
instead of a Student
. How can I fix the GenerateRandomInstance
method so it returns a Student instead of a Person. Casting a person to student gives me an error
Upvotes: 4
Views: 6029
Reputation: 12811
Try something like this. Person
and Student
each define their own GenerateRandomInstance
and RandomizeProperties
methods. Student
calls Person
's RandomizeProperties
to let the base class randomize the properties that it knows about. Student
would then only randomize the properties that are introduced by the Student
class.
NOTE: This problem is often solved by the Abstract Factory or Builder design patterns. The solution below is neither of those.
class Person
{
public string Name { get; set; }
public virtual void Speak()
{
Console.Write("Hello I am a person");
}
public static Person GenerateRandomInstance()
{
var o = new Person();
RandomizeProperties(o);
return o;
}
protected static void RandomizeProperties(Person o)
{
// randomize Person properties here
}
}
class Student : Person
{
public override void Speak()
{
Console.Write("Hello I am a student");
}
// note the use of the 'new' keyword
new public static Student GenerateRandomInstance()
{
var o = new Student();
RandomizeProperties(o);
return o;
}
protected static void RandomizeProperties(Student o)
{
Person.RandomizeProperties(o);
// randomize Student properties here
}
}
Upvotes: 2
Reputation: 149030
You can't. A static method cannot be overridden in a child class and there's no way to distinguish between Student.GenerateRandomInstance
and Person.GenerateRandomInstance
—in fact they generate exactly the same CIL when compiled.
You could use a generic method instead:
public static T GenerateRandomInstance<T>() where T : Person, new
{
var p = new T();
// randomize properties
return p;
}
Person.GenerateRandomInstance<Student>();
But this will only work if the type has a parameterless constructor. If you'd like to pass arguments to the constructor, it becomes somewhat more difficult. Assuming you always know what values you want to pass to the constructor you can do this:
public static T GenerateRandomInstance<T>() where T : Person
{
var p = (T)Activator.CreateInstance(typeof(T), "hello", 4);
// randomize properties
return p;
}
Of course, this too will fail if the specified type does not contain a suitable constructor.
Upvotes: 5
Reputation: 5689
You need to override the GenerateRandomInstance()
method in your Student class. currently the base method in Person is being called.
Upvotes: 1