简体   繁体   中英

Can a derived generic type be returned from a static method on the base abstract class?

Abstract class:

abstract class PersistentList<T>

public static PersistentList<T> GetInstanceOfDerivedClass()
{
    //???
}

Derived class:

public class Managers : PersistentList<Manager> 

So, I'd like to:

Managers managers = Managers.GetInstanceOfDerivedClass();

Is that possible?

Choices are:

int clientID = 3;

Managers managers = Managers.For("Client", new { ClientID = clientID});

Managers managers = new Managers(new { ClientID = clientID });

Managers managers = new Managers();
managers.ClientID = clientID;
managers.Load("ForClient");
//alternatively:
Database.Load(managers, "ForClient");

//this works, however requires the above code in the constructor.
Managers managers = new Managers(clientID);

//If the static method on the abstract class (Managers.For) could determine
//the type calling, it would eliminate the need for repetitive constructors.

All the above are available, just trying to decide on a good technique.

You can't do it with a static method. I'm not sure why you would want to, but you can do this

    public abstract class PersistentList<T>
    {
        public PersistentList<T> GetInstanceOfDerivedClass()
        {
            return (PersistentList<T>)Activator.CreateInstance(this.GetType());
        }
    }

Usage

Managers managers = (Managers)new Managers().GetInstanceOfDerivedClass();

I think this is about the simplest it'll be if you need strong typing (ie that the method will return Managers , not just PersistentList<Manager> when requesting a Managers ):

static class PersistentList
{
    public static T GetInstanceOfDerivedClass<T, U>() where T : PersistentList<U>
    {
        throw new NotImplementedException();
    }
}

Managers managers = PersistentList.GetInstanceOfDerivedClass<Managers, Manager>();

You might also do:

abstract class PersistentList<T, U> where T : PersistentList<T, U>
{
    public static T GetInstanceOfDerivedClass()
    {
        throw new NotImplementedException();
    }
}
public class Managers : PersistentList<Managers, Manager>
{
}

This lets you use the signature in your example, Managers.GetInstanceOfDerivedClass() . I find this design pattern confusing, however, and would discourage its use.

This seems like an odd situation to be in but assuming you are somehow confined to such a pattern, this is the closest thing I could come up with (still not exactly what you are trying to do):

abstract class PersistentList<T>
{
    public static T2 GetInstanceOfDerivedClass<T2>() where T2 : PersistentList<T>
    {
        return (T2)Activator.CreateInstance(typeof(T2));
    }
}

class Manager { }

class Managers : PersistentList<Manager> { }

Usage:

Managers managers = PersistentList<Manager>.GetInstanceOfDerivedClass<Managers>();

One could use a pattern like you describe, but in some cases it may be useful to have the factory method be a generic method within a non-generic static class, especially if the method will take any parameters which could be used for type inference. For example, if one had a method to create a new collection which would be initially populated from a T[] , it may in some cases be more convenient to use SuperCollection<T> SuperCollection.Create<T>(T InitialValues[]) than SuperCollection<T> SuperCollection<T>.Create(T InitialValues[]) , since the former could automatically infer the type of collection to create based upon the type of the array parameter.

Other than that, I think what you describe is a perfectly reasonable pattern in cases where the type of object which is created may depend upon various factors which might not be known at compile time.

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