Oliver Kane
Oliver Kane

Reputation: 898

C# How to make a factory method return of the subclass type

[MAJOR EDITS, my first post was somewhat misleading. My appologies]

Given a class such as:

public class DatabaseResult{
    public bool Successful;
    public string ErrorMessage;     

    //Database operation failed
    public static DatabaseResult Failed(string message) {
         return new DatabaseResult{
             Successful = true,
             ErrorMessage = message
         };
    }
}

How can I implement subclasses such that I can add additional properties to represent data relevant to the particular operation (such as MatchedResult in the case of a SELECT type query) without the need to implement that static failure function? If I try to use plain inheritance, the return type will be of the parent class. Eg:

DoThingDatabaseResult : DatabaseResult {
     public IEnumerable<object> SomeResultSet;
     public static Successful(IEnumerable<object> theResults){
          return new DoThingDatabaseResult {
               Successful = true,
               ErrorMessage = "",
               SomeResultSet = theResults
          };
     }
     //public static DatabaseResult Failed exists, but it's the parent type!
}

The goal is to avoid needing to copy the Failed static function for every subclass implementation.

Upvotes: 4

Views: 1820

Answers (4)

Les
Les

Reputation: 10605

If I may, I'd like to expand upon StriplingWarrior. In fact, you can use static for the factory. This following code shows that a and c are the expected object types. The limit is you cannot use the factory on the base class itself.

 private void Testit()
    {
        var a = SavingsAccount.Factory();
        var c = CheckingAccount.Factory();
        //var b = BankAccount.Factory(); //can't do this
    }


public class BankAccount<T> where T : BankAccount<T>, new()
{
    public static T Factory()
    {
        return new T();
    }
}

public class SavingsAccount : BankAccount<SavingsAccount>
{
}

public class CheckingAccount : BankAccount<CheckingAccount>
{
}

Upvotes: 1

Tim Copenhaver
Tim Copenhaver

Reputation: 3302

You can't do this exactly as you have defined the question. The best way to tackle this is really to pull your factory out of the class completely:

public class BankAccount
{
}

public class SavingsAccount : BankAccount
{
}

public static class BankAccountFactory
{
    public static T Create<T>() where T : BankAccount, new()
    {
        return new T();
    }
}

Now the Factory has no dependency on the actual type. You can pass any derived class of BankAccount and get it back without doing any extra work or worrying about inheriting your factory method.

Upvotes: 2

Kyle W
Kyle W

Reputation: 3752

In order to use inheritance, you need an instance of an object and a member of that object. In this case, for the object we can't use BankAccount/SavingsAccount because then we would already have what we're trying to get. This means we need an actual factory object, which is what most people are talking about when they talk about a factory. So if we pull that out into a Factory and use inheritance...

public class BankAccountFactory { public virtual GetAccount() { return new BankAccount(); } }
public class SavingsAccountFactory : BankAccountFactory { public override GetAccount() { return new SavingsAccount(); } }

But now how do we get an instance of the proper type? We've just pushed our problem one layer deeper.

Instead, what you probably want to do, is use some sort of configuration to determine the type, or pass the type you want into a method.

public BankAccount GetAccount(AccountType type) { /* */ }

or

public BankAccount GetAccount() { /* Access config */ }

For a simple answer to your question: You don't need to use generics or anything like that, you just need your method to not be static...

Upvotes: 0

StriplingWarrior
StriplingWarrior

Reputation: 156469

Make it recursively generic:

public class BankAccount<T> where T : BankAccount<T>, new()
{
    public T SomeFactoryMethod() { return new T(); }
}

public class SavingsAccount: BankAccount<SavingsAccount>{}

You'll note that I made the factory method non-static, because static methods aren't inherited.

Upvotes: 4

Related Questions