如何创建匿名 class 以便将其传递给通用构造函数?
How to create anonymous class so that it can be passed to generic constructor?
我正在将非通用存储库的测试移植到通用存储库。我不想使用 Repo<MyType>
,而是想用 Repo<object>
或其他东西来测试更抽象的方法。
我尝试使用匿名 实例,但没有成功:
[Test]
public void AddToRepoIncrementsByOne()
{
IFile file = new FileFake();
IByteSerializer<object> serializer = new SerializerObjectFake();
repo = new WriteableFileRepository<object>(file, serializer);
var obj = new { Name = "test" };
repo.Add(obj);
Assert.True(repo.Items.Count() == 1);
Assert.AreEqual(repo.Items.Single().Name, obj.Nome);
//----------------------------------^^^^
//-------------------compiler error here
}
我试图从对象中推断出 class 引用,但也没有成功:
var obj = new { Nome = "teste" };
Type T = obj.GetType();
IArquivo arquivo = new ArquivoFake();
IByteSerializer<T> serializer = new SerializerObjectFake();
//--------------^
repo = new RepositórioArquivoEscrita<T>(arquivo, serializer);
我该如何解决这个问题?我并不要求使用匿名对象,我只是认为这是一种实用的测试方式 运行,但如果这不是一个好的设计,我肯定可以用其他方式来做。
解决此问题的最简单方法是通过使用 obj
的通用方法让编译器填充空白:
var obj = new { Nome = "teste" };
Foo(obj);
...
void Foo<T>(T obj) {
IArquivo arquivo = new ArquivoFake();
IByteSerializer<T> serializer = new SerializerObjectFake();
// etc
}
现在T
是匿名类型
而不是这个:
IByteSerializer<object> serializer = new SerializerObjectFake();
repo = new WriteableFileRepository<object>(file, serializer);
创建一个通用方法来创建您的存储库:
RepoType<T> CreateRepository<T>(IFile file, T objectForType)
{
IByteSerializer<T> serializer = new SerializerObjectFake();
return new WriteableFileRepository<T>(file, serializer);
}
用法:
[Test]
public void AddToRepoIncrementsByOne()
{
IFile file = new FileFake();
var obj = new { Name = "test" };
/*Your type is missing*/ repo = CreateRepository(file, obj);
repo.Add(obj);
Assert.True(repo.Items.Count() == 1);
Assert.AreEqual(repo.Items.Single().Name, obj.Nome);
//----------------------------------^^^^
//-------------------no more error here
}
通过将您的匿名对象作为参数传递(即使您不使用它),它允许您将其类型作为通用参数。然后,您可以使用它根据其类型实例化对象。
匿名类型的技巧是通过示例进行转换;让编译器利用类型推断为您完成工作:
public static T CastByExample(this object obj, T prototype) =>
(T)obj;
现在您需要做的就是:
Assert.AreEqual(repo.Items.Single().CastByExample(obj).Name, obj.Name);
我正在将非通用存储库的测试移植到通用存储库。我不想使用 Repo<MyType>
,而是想用 Repo<object>
或其他东西来测试更抽象的方法。
我尝试使用匿名 实例,但没有成功:
[Test]
public void AddToRepoIncrementsByOne()
{
IFile file = new FileFake();
IByteSerializer<object> serializer = new SerializerObjectFake();
repo = new WriteableFileRepository<object>(file, serializer);
var obj = new { Name = "test" };
repo.Add(obj);
Assert.True(repo.Items.Count() == 1);
Assert.AreEqual(repo.Items.Single().Name, obj.Nome);
//----------------------------------^^^^
//-------------------compiler error here
}
我试图从对象中推断出 class 引用,但也没有成功:
var obj = new { Nome = "teste" };
Type T = obj.GetType();
IArquivo arquivo = new ArquivoFake();
IByteSerializer<T> serializer = new SerializerObjectFake();
//--------------^
repo = new RepositórioArquivoEscrita<T>(arquivo, serializer);
我该如何解决这个问题?我并不要求使用匿名对象,我只是认为这是一种实用的测试方式 运行,但如果这不是一个好的设计,我肯定可以用其他方式来做。
解决此问题的最简单方法是通过使用 obj
的通用方法让编译器填充空白:
var obj = new { Nome = "teste" };
Foo(obj);
...
void Foo<T>(T obj) {
IArquivo arquivo = new ArquivoFake();
IByteSerializer<T> serializer = new SerializerObjectFake();
// etc
}
现在T
是匿名类型
而不是这个:
IByteSerializer<object> serializer = new SerializerObjectFake();
repo = new WriteableFileRepository<object>(file, serializer);
创建一个通用方法来创建您的存储库:
RepoType<T> CreateRepository<T>(IFile file, T objectForType)
{
IByteSerializer<T> serializer = new SerializerObjectFake();
return new WriteableFileRepository<T>(file, serializer);
}
用法:
[Test]
public void AddToRepoIncrementsByOne()
{
IFile file = new FileFake();
var obj = new { Name = "test" };
/*Your type is missing*/ repo = CreateRepository(file, obj);
repo.Add(obj);
Assert.True(repo.Items.Count() == 1);
Assert.AreEqual(repo.Items.Single().Name, obj.Nome);
//----------------------------------^^^^
//-------------------no more error here
}
通过将您的匿名对象作为参数传递(即使您不使用它),它允许您将其类型作为通用参数。然后,您可以使用它根据其类型实例化对象。
匿名类型的技巧是通过示例进行转换;让编译器利用类型推断为您完成工作:
public static T CastByExample(this object obj, T prototype) =>
(T)obj;
现在您需要做的就是:
Assert.AreEqual(repo.Items.Single().CastByExample(obj).Name, obj.Name);