更新两个常用函数以使用泛型

时间:2012-10-21 14:51:20

标签: c# .net generics

如果您需要在另一个项目中测试非公共属性,则使用Microsoft单元测试向导创建Accessor对象。在我的单元测试中,我创建了辅助函数,这样我就不会在每个单元测试方法中重复相同的代码。目前我有两个几乎相同的测试,除了一个采用标准对象,另一个采用Accessor版本。由于Accessor基于标准版本,我应该能够拥有一个功能,我认为我应该能够使用Generics来完成。问题是尝试重新输入和编译失败。

以下是现有的两个功能:

// Common function to create a new test record with standard Account object
internal static void CreateAccount(out Account account, bool saveToDatabase)
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = new Account(created, createdBy);

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

// Common function to create a new test record with Account_Accessor
internal static void CreateAccount(out Account_Accessor account, bool saveToDatabase)
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = new Account_Accessor(created, createdBy);

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

我尝试将签名更改为组合函数:

internal static void CreateAccount<T>(out T account, bool saveToDatabase) {...}

但无法正确地重新计算帐户或帐户_Accessor。有什么建议?

2 个答案:

答案 0 :(得分:3)

您应该为泛型函数添加约束,因为这两种方法:

account.Notes = Utilities.RandomString(1000);
account.Create();

我建议你用这两种方法添加一些接口,并将它的继承添加到你的两个类中。 约束应如下:

where T : YourNewInterface

关于约束,您可以在http://msdn.microsoft.com/en-us/library/bb384067.aspx上阅读
更新

public interface IAccount
    {
        string Notes { get; set; }
        void Create();
        void Init(DateTime created, string createdBy);
    }

public class Account : IAccount
{
    public string Notes
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void IAccount.Create()
    {
        throw new NotImplementedException();
    }

    void IAccount.Init(DateTime created, string createdBy)
    {
        throw new NotImplementedException();
    }
}

public class Account_Accessor : IAccount
{

    string IAccount.Notes
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void IAccount.Create()
    {
        throw new NotImplementedException();
    }

    void IAccount.Init(DateTime created, string createdBy)
    {
        throw new NotImplementedException();
    }
}


class Program
{
    internal static void CreateAccount<T>(out T account, bool saveToDatabase) where T : IAccount,new()
    {
        DateTime created = DateTime.Now;
        string createdBy = _testUserName;

        account = new T();
        account.Init(created, createdBy);

        account = (T)Activator.CreateInstance(typeof(T), new object[] { created, createdBy });

        account.Notes = Utilities.RandomString(1000);

        if (saveToDatabase)
            account.Create();
    }
    static void Main(string[] args)
    {
        Account acc;
        Account_Accessor acc2;
        CreateAccount(out acc, false);
        CreateAccount(out acc2, false);
    }
}

以下是关于我的例子的一些评论:
1.我通过添加CreateInstance约束来替换new() 2.由于.NET泛型限制因为new()约束不能有参数,我在Init()接口添加了IAccount方法。
3. Init类的客户端代码不应该调用Account方法,这就是为什么我们将方法定义为私有和显式为IAccount。
4.由于new()约束,您应该为Account提供无参数构造函数。如果您这样做,您的客户端代码不应该调用此无参数的ctor
至于我,我会按原样离开Activator.CreateInstance。对于通用new()约束

的限制,这是一个很好的解决方法

答案 1 :(得分:0)

这是我对该方法的通用性的看法。

public abstract class BaseAccount
{
    public string Notes;

    public virtual void Create() { ... }
}

public class Account : BaseAccount { ... }

public class Account_Accessor : BaseAccount { ... }

internal static void CreateAccount<T>(out T account, bool saveToDatabase) where T : BaseAccount
{
    DateTime created = DateTime.Now;
    string createdBy = _testUserName;

    account = (T)Activator.CreateInstance(typeof(T), new object[] { created, createdBy });

    account.Notes = Utilities.RandomString(1000);

    if (saveToDatabase)
        account.Create();
}

我认为Account和Account_Accessor足够相似,可以共享类似的类层次结构,或者可以实现相同的接口。在这个例子中,我提供了一个抽象类,它们都是从中派生出来的,但是用接口来实现它很容易。但是,必须在两个类中完成全部实现。

知道这一点,我可以约束泛型方法,以便T只是BaseAccount的子节点。这样,我可以在不知道T的实际类型的情况下从该基类访问成员。