我可以用泛型类型来解决这个问题吗?

时间:2009-07-19 20:02:12

标签: c# generics

这是我想要的类结构:

  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当然是这个方案崩溃的地方。我需要一个Allocations集合才能在这个类中使用,但是在客户端使用ClockIn方法之前我不知道TResource会是什么。

我一直坚持如何用资源和活动类型解决分配类的各种想法,所以我希望我遗漏了一些明显的东西。看起来应该可以用Generics来解决。

干杯

更多信息

以下是一些活动示例:

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

以下是资源示例:

public class StaffMemberResource : AllocatableResource<StaffMember>
{
    public StaffMemberResource(StaffMember staffMember) {
        Description = staffMember.Name.ToString();
        BusinessId = staffMember.Number;
    }
}

数据输入将由单个资源进行。我还不知道递归问题,但除此之外没有商业原因为什么TResource不能在数据输入会话中被知道而不是创建活动的成本(大约有300个基础项目组合,账户我我想在此时将其视为AllocatableActivity。

报告涉及多个资源(即,管理者需要按时花费时间来查看所分配资源所花费的所有时间,按项目进行临时报告等)。

我在没有泛型(接口和基类)的情况下铺设了这个,但是涉及打字时有一些尴尬,所以我想看看泛型是否会产生更简单的界面。

4 个答案:

答案 0 :(得分:2)

AllocatableActivity<TActivity>为什么TResource也不通用?这将使语言一切顺利 - 这是否存在业务问题?您能举例说明TActivityTResource,以及为什么您可能不知道创建活动时需要哪种资源?

答案 1 :(得分:1)

为了在AllocatableActivity中拥有统一存储,我将为Allocation和所有资源类型提供一个抽象基类,如下所示:

public abstract class Resource
{
    public string Description { get; }
}

public class AllocatableResource<TResource> where TResource : Resource
{
    ...
}

public abstract class Allocation<TActivity>
{
    protected Allocation(
        Resource resource, TActivity activity, TimeQuantity period)
    {
        this.Resource = resource;
        this.Activity = activity;
        this.Period = period;
    }

    public virtual Resource Resource { get; protected set; }
    public TActivity Activity { get; protected set; }
    public TimeQuantity Period { get; protected set; }
}

public class Allocation<TActivity, TResource> : Allocation<TActivity>
    where TActivity : AllocatableActivity<TActivity>
    where TResource : AllocatableResource<TResource>
{
    public new TResource Resource { get; private set; }

    public Allocation(
        TResource resource, TActivity activity, DateTime eventDate,
        TimeQuantity timeSpent)
        : base(resource, activity, timeSpent)
    {
        ...
    }
}

现在,在AllocatableActivity中,您可以以多态方式存储所有分配,如下所示:

public class AllocatableActivity<TActivity>
{
    protected readonly IDictionary<DateTime, Allocation<TActivity>> _allocations;

    public virtual void ClockIn<TResource>(
        DateTime eventDate, TResource resource, TimeQuantity timeSpent) 
        where TResource : Resource
    {
        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);
    }
}

我添加基础资源类的原因是你无疑需要在应用程序的某个地方列出资源,所以应该有某种共性。

答案 2 :(得分:1)

where TActivity : AllocatableActivity<TActivity>的定义中有Allocation,但ProjectActivity : AllocatableActivity<Project> 满足此约束(活动/资源的所有其他示例都没有) !它应该是ProjectActivity : AllocatableActivity<ProjectActivity>吗?

鉴于您对AllocatableResource的定义,为什么要将其设为通用?您不使用该参数,它只会使您的任务复杂化;只需将它作为资源的基类并具有

public class Allocation<TActivity> 
    where TActivity : AllocatableActivity<TActivity>
{

    public AllocatableResource Resource { get; private set; }
    public TActivity Activity { get; private set; }
    public TimeQuantity Period { get; private set; }

    public Allocation(AllocatableResource 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 AllocatableActivity<TActivity>
{

    public string Description { get; protected set; }
    public string BusinessId { get; protected set; }

    protected readonly IDictionary<DateTime, Allocation<TActivity>> _allocations;

    public virtual void ClockIn(DateTime eventDate, AllocatableResource resource, TimeQuantity timeSpent)
    {
        var entry = new Allocation<TActivity>(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);
    }
}

答案 3 :(得分:0)

虽然目前还不完全清楚你要完成什么,但这是我所看到的一般意义......

您拥有将用于TActivityTResource的现有(或新)业务对象。您的AllocatableActivity类代表一个TActivity,其中包含TResource的多个实例(可能是不同的类型)。

另一方面,你有一个AllocationNEW类代表一个AllocatableActivity和一个AllocatableResource(硬币的另一面,就像它一样)。这是一个活动 - 资源相关类。

你所拥有的与在关系数据库中拥有多对多关系非常相似。您有活动,拥有资源,并且您有一个activity_resource表,允许您链接它们。

在没有使用反射的情况下,我没有看到支持所有这一切的单一解决方案(我不知道在这种情况下会有什么结果)。您可能需要的是为AllocationNEW创建一个非泛型抽象基类,它将资源的属性公开为公共基类型(即使最接近的是object),然后使用您的通用实现继承并公开自己的强类型属性(或者,对于“更干净”的方法,让它用强类型版本替换父弱类型属性)。在您的AllocatableActivity课程中,您的收藏集应该是IDictionary<DateTime, AllocationNEWBase>,因为您无法知道TResource的具体类型(并且不希望将其限制为特定类型,如果我之前的假设是正确的)。在ClockIn中,您可以使用TResource类型参数来实例化强类型通用版本。