Reputation: 18746
Given a base class in which we are supposed to use static factory methods to construct all derived classes, how would I bind such that derived types are created by the base factory?
public abstract class BusinessObject<T> where T : BusinessObject<T>, new()
{
#region Member Variables
/// <summary>
/// Object that acts as a lock when retrieving or creating the singleton instance.
/// </summary>
private static object singletonLock = new object();
/// <summary>
/// Singleton instance of this business object with default connection string.
/// </summary>
private static T instance;
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endregion Member Variables
#region Properties
/// <summary>
/// Gets the connection string.
/// </summary>
/// <value>The connection string.</value>
public virtual string ConnectionString { get; protected set; }
/// <summary>
/// Default connection string for business object.
/// </summary>
protected virtual string DefaultConnectionString { get { return ConfigurationManager.ConnectionStrings["LocalSqlConnection"].ConnectionString; } }
/// <summary>
/// Creates or retrieves the singleton instance of this business object.
/// </summary>
public static T Instance { get { return GetInstance(); } }
protected static log4net.ILog Log { get { return log; } }
#endregion Properties
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="BusinessObject"/> class.
/// </summary>
protected BusinessObject()
{
ConnectionString = DefaultConnectionString;
}
#endregion Constructor
#region Methods
/// <summary>
/// Returns singleton business object using default connection string.
/// </summary>
public static T GetInstance()
{
if (instance != null)
return instance;
// If instance has not been created, create new instance (with thread-safe lock).
lock (singletonLock)
{
if (instance == null)
instance = new T();
}
return instance;
}
/// <summary>
/// Returns new instance of business object using custom connection string.
/// </summary>
public static T GetInstance(string connectionString)
{
return new T() { ConnectionString = connectionString };
}
#endregion Methods
}
Sample snippet of derived class:
public class ProjectBO : BusinessObject<ProjectBO>
{
#region Constructors
[Obsolete("Use instance property instead", false)]
public ProjectBO() { }
static ProjectBO()
{
quotaGroupBlacklist = new List<int>();
unavailableQuotaGroupsByMember = new Dictionary<int, List<int>>();
unavailableProjectsByMember = new Dictionary<int, List<int>>();
}
#endregion Constructors
}
so I want to (by convention) hook up all derived types to use the base class factory method GetInstance(string)
how can I do this without changing the base or derived classes?
Upvotes: 0
Views: 485
Reputation: 13243
This is how you could do that:
this.Bind(x => x
.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(typeof(BusinessObject<>))
.BindWith<BusinessObjectBindingGenerator>());
public class BusinessObjectBindingGenerator : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
yield return bindingRoot
.Bind(type)
.ToMethod(ctx => CreateBusinessObject(type));
}
private static object CreateBusinessObject(Type type)
{
return typeof(BusinessObject<>)
.MakeGenericType(type)
.GetMethod("GetInstance", BindingFlags.Static | BindingFlags.Public)
.Invoke(null, new object[0]);
}
}
Disclaimer: i didn't test the reflection stuff but i think it's correct.
Also note that i think it's bad design. I think it's a bit smelly.
Why are you even using the .GetInstance
method? You could just as easily replace it with:
this.Bind(x => x
.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(typeof(BusinessObject<>))
.BindToSelf()
.Configure(x => x.InSingletonScope()));
Upvotes: 1