简体   繁体   中英

Static method return an object of it's containing class type

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

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.

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
    }
}

You need to override the GenerateRandomInstance() method in your Student class. currently the base method in Person is being called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM