Here is the class structure I'd like to have:
public class AllocationNEW<TActivity, TResource>
where TActivity : AllocatableActivity<TActivity>
where TResource : AllocatableResource<TResource>
{
public TResource Resource { get; private set; }
public TActivity Activity { get; private set; }
public TimeQuantity Period { get; private set; }
public AllocationNEW(TResource resource, TActivity activity, DateTime eventDate, TimeQuantity timeSpent)
{
Check.RequireNotNull<IResource>(resource);
Resource = resource;
Check.RequireNotNull<Activities.Activity>(activity);
Activity = activity;
Check.Require(timeSpent.Amount >= 0, Msgs.Allocation_NegativeTimeSpent);
TimeSpentPeriod = _toTimeSpentPeriod(eventDate, timeSpent);
}
}
public class AllocatableResource<TResource>
{
public string Description { get; protected set; }
public string BusinessId { get; protected set; }
}
public class AllocatableActivity<TActivity>
{
public string Description { get; protected set; }
public string BusinessId { get; protected set; }
protected readonly IDictionary<DateTime, Allocation<TActivity, TResource>> _allocations;
public virtual void ClockIn<TResource>(DateTime eventDate, TResource resource, TimeQuantity timeSpent)
{
var entry = new Allocation<TActivity, TResource>(resource, this, eventDate, timeSpent);
if (_allocations.ContainsKey(eventDate))
{
Check.Require(_allocations[eventDate].Resource.Equals(resource),
"This method requires that the same resource is the resource in this allocation.");
_allocations[eventDate] = entry;
}
else _allocations.Add(eventDate, entry);
}
}
AllocatableActivity is where this scheme breaks down, of course. I need a collection of Allocations to work with in this class, but I don't know what TResource is going to be until a client uses the ClockIn method.
I've been stuck on various ideas on how to solve the Allocation class with Resource and Activity types for awhile, so I'm hoping that I'm missing something obvious. It seems like it should be solvable with Generics.
Cheers
MORE INFO
Here's some examples of activities:
public class ProjectActivity : AllocatableActivity<Project>
{
public ProjectActivity(Project project) {
_project = project;
Description = _project.Description;
BusinessId = _project.Code.ToString();
}
// private readonly Project _project; --> shouldn't need anymore
}
public class AccountingActivity : AllocatableActivity<Account>
{
public AccountingActivity(Account account)
{
_account = account;
Description = account.Description;
BusinessId = account.AccountId;
}
// private readonly Account _account;
}
Here's an example of a resource:
public class StaffMemberResource : AllocatableResource<StaffMember>
{
public StaffMemberResource(StaffMember staffMember) {
Description = staffMember.Name.ToString();
BusinessId = staffMember.Number;
}
}
Data entry would be by a single Resource. I don't know about the recursion issue yet, but otherwise there is no business reason why TResource can't be known in a data entry session other than the cost of creating the activities (there's about 300 combinations of underlying projects, accounts that I would want to treat as an AllocatableActivity at this time.
Reporting would involve multiple resources (ie, a Manager needing to sign off on time spent needs to see all time spent by her assigned resources, ad hoc reports by project, etc.)
I was laying this out without generics (interfaces and base classes) but there was some awkwardness with involving the typing, so I wanted to see if generics would make for a simpler interface.