2

別のプロジェクトで非公開プロパティをテストする必要がある場合は、Microsoft単体テストウィザードを使用してAccessorオブジェクトを作成します。単体テスト内でヘルパー関数を作成して、すべての単体テストメソッドで同じコードを繰り返さないようにします。現在、1つは標準オブジェクトを取得し、もう1つはAccessorバージョンを取得することを除いて、ほぼ同じ2つのテストがあります。アクセサーは標準バージョンに基づいているので、私は1つの機能を持つことができるはずであり、ジェネリックを使用して達成できるはずだと思います。問題は、失敗を再入力してコンパイルしようとしています。

既存の2つの関数は次のとおりです。

// 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) {...}

しかし、TをAccountまたはAccount_Accessorに正しくリキャストできませんでした。助言がありますか?

4

2 に答える 2

3

この2つの方法のため、総称関数に制約を追加する必要があります。

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

この2つのメソッドを使用してインターフェイスを追加し、そこから2つのクラスに継承を追加することをお勧めします。制約は次のようになります。

where T : YourNewInterface

制約については、 http://msdn.microsoft.com/en-us/library/bb384067.aspxUPDATE読むことができます。

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 。制約を追加し
て置き換えました。 2. .NETジェネリック制限のため、new()制約はパラメーターを持つことができないため、インターフェースにメソッドを追加しました。 3.メソッドは、クラスのクライアントコードによって呼び出されるべきではありません。そのため、メソッドをプライベートとして定義し、IAccountに対して明示的に定義します。 4.制約があるため、のパラメーターなしのコンストラクターを提供する必要があります。これを行う場合、クライアントコードはこのパラメーターなしのctorを呼び出さないでください。 私はそのままにしておきます。一般的な制約の制限に対する適切な回避策です。CreateInstancenew()
Init()IAccount
InitAccount
new()Account

Activator.CreateInstancenew()

于 2012-10-21T15:00:22.323 に答える
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の実際のタイプを知らなくても、その基本クラスのメンバーにアクセスできます。

于 2012-10-21T16:01:55.317 に答える