C# 更新两个常用函数以使用共享函数的最佳方法

C# 更新两个常用函数以使用共享函数的最佳方法,c#,.net,C#,.net,如果需要从其他项目测试非公共属性,Microsoft单元测试向导将创建访问器对象。在我的单元测试中,我创建了helper函数,这样我就不会在每个单元测试方法中重复相同的代码。目前,我有两个几乎相同的测试,除了一个采用标准公共对象,另一个采用访问器版本。因为访问器基于公共对象,所以我应该能够有一个函数。我假设我可以使用泛型来完成一个简单的转换。但当我发现这需要做更多的工作,包括更新底层对象。我的问题是使用强制转换(或其他)方法将这些冗余方法减少为只有一个函数的另一种方法 以下是现有的两个功能: /

如果需要从其他项目测试非公共属性,Microsoft单元测试向导将创建访问器对象。在我的单元测试中,我创建了helper函数,这样我就不会在每个单元测试方法中重复相同的代码。目前,我有两个几乎相同的测试,除了一个采用标准公共对象,另一个采用访问器版本。因为访问器基于公共对象,所以我应该能够有一个函数。我假设我可以使用泛型来完成一个简单的转换。但当我发现这需要做更多的工作,包括更新底层对象。我的问题是使用强制转换(或其他)方法将这些冗余方法减少为只有一个函数的另一种方法

以下是现有的两个功能:

// 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();
}
我有24个这样的单元测试,实际对象平均有10个属性,我简化了这里的示例

下面是单元测试API创建的访问器代码(同样,为了简化示例,我对其进行了简化):

使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用制度;
使用System.Collections.ObjectModel;
使用系统数据;
名称空间NameHere.Bll
{
[隐藏(“NameHere.Bll.Account”)]
公共类帐户\u访问器:ProjectBase\u访问器
{
受保护的静态PrivateType m_PrivateType;
公共帐户访问器(PrivateObject值);
[阴影(“。ctor@2")]
公共帐户访问器(创建日期时间,创建字符串);
[阴影(“_注释”)]
公共字符串_notes{get;set;}
公共静态帐户\访问器AttachShadow(对象值);
[阴影(”Create@0")]
公共覆盖void Create();
}
}
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用制度;
使用系统组件模型;
使用System.Linq.Expressions;
名称空间NameHere.Bll
{
[隐藏(“NameHere.Bll.ProjectBase`1”)]
公共类ProjectBase\u访问器:BaseShadow,INotifyPropertyChanged
{
受保护的静态PrivateType m_PrivateType;
公共项目库访问器(PrivateObject值);
[阴影(“创建”)]
已创建公共日期时间{get;set;}
公共静态私有类型ShadowedType{get;}
[阴影(“添加_PropertyChanged@1")]
public void add_PropertyChanged(propertychangedventhadler值);
公共静态项目库\访问器AttachShadow(对象值);
[阴影(”Create@0")]
公共虚拟void Create();
}
}

问题在于,尽管访问器类公开了与其所隐藏的类相同的方法和属性,但在访问器和原始类之间没有公共接口。帐户\访问器继承自BaseShadow,帐户继承自其他内容。就编译器而言,它们是完全不相关的类型,不兼容赋值,因此很难将每个类型的实例传递到公共例程中

如果可以强制Account_访问器类实现也由Account实现的接口类型,则可以将每个接口类型的实例传递给以接口类型为参数的函数。像这样:

internal static IAccount SetupAccount(IAccount account, bool saveToDatabase)
{
// do account setup here - not construction
}

// to call: construct instance, then pass to common function
var account = new Account(a, b);
SetupAccount(account, true);
如果Account实例的构造非常复杂,您也希望有一个通用例程,请将特定于类型的包装放在通用函数前面:

internal static IAccount CreateAccount(bool saveToDatabase)
{
    var account = new Account(a,b);
    return SetupAccount(account, saveToDatabase);
}

internal static IAccount CreateAccountAccessor(bool saveToDatabase)
{
    var account = new Account_Accessor(a,b);
    return SetupAccount(account, saveToDatabase);
}
你无法逃避的一点是:某个地方的某个人必须提交要构造的实例。即使您将其归结为传递类型并使用
Activator.CreateInstance()
,也必须有人承诺选择要使用的类型


一旦构建了实例,并且这两种类型都实现了一个公共接口,那么所有的公共功能都需要关心的是公共接口。

Account和
Account\u Accessor
之间有什么区别?忽略我的答案。显然,这和你的另一个问题的答案是一样的。换句话说,我认为泛型实际上是用最少的工作量来完成的方法。我在问题中添加了代码访问器代码,正如@dthorpe所指出的,访问器继承自BaseShadow(在它经过我们的基类之后)。感谢您提供的详细信息。如果我们只是传递一个对象并尝试强制转换为Account或Account_访问器,我假设我们也会遇到同样的问题,因为这两个对象不是从同一个源继承的。正确。您可以创建参数类型对象,但要进行方法调用,必须将该对象类型转换为特定类型(Account或Account\u访问器)。由于这两种类型不相关,这意味着每当您的公共代码想要对对象执行某些操作时,您必须分支/使用if语句。可能不值得这么麻烦。一种前卫的可能性可能是尝试在公共例程中使用动态对象。动态对象是后期绑定类型,类似于JavaScript的工作方式。理论上,这意味着在对象上查找“foo”方法不是在编译时发生的,而是在运行时发生的,因此无论涉及哪个对象实例,它都可能在运行时发现相同的命名方法。我对dynamic不够熟悉,无法提供实现建议,但它可能值得研究。
internal static IAccount CreateAccount(bool saveToDatabase)
{
    var account = new Account(a,b);
    return SetupAccount(account, saveToDatabase);
}

internal static IAccount CreateAccountAccessor(bool saveToDatabase)
{
    var account = new Account_Accessor(a,b);
    return SetupAccount(account, saveToDatabase);
}