在为OSS 项目做贡献的同时,我遇到了 TypeLoadException。我正在创建一个接缝,开发人员可以通过该接缝注入他们自己的 Repository 类来删除对 EF 的具体依赖,这样我就可以隔离我的新代码并运行一些测试。
似乎Activator.CreateInstance()
针对具有嵌套类型 arg 的类型运行会在运行时创建它时遇到麻烦。我以前多次使用过这种模式,但这次不同的是我使用它来动态注入一个通用的存储库模式实现。问题似乎确实与该类型 arg 有关。我目前很难过,所以任何帮助将不胜感激。
这是我得到的错误:
System.TypeLoadException: Could not load type 'Rock.Tests.Fakes.FakeRepository' from assembly 'Rock.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, ref StackCrawlMark stackMark)
at System.Activator.CreateInstance(String assemblyName, String typeName)
at Rock.Data.RepositoryFactory`1.FindRepository() in RepositoryFactory.cs: line 30
at Rock.Data.Service`1..ctor() in Service.cs: line 34
at Rock.Core.AttributeService..ctor()
at Rock.Attribute.Helper.LoadAttributes(IHasAttributes item) in Helper.cs: line 165
at Rock.Data.ModelWithAttributes`1.get_Attributes() in ModelWithAttributes.cs: line 38
at Rock.CMS.Page.MapPagesRecursive(Page page) in Page.cs: line 422
at Rock.CMS.Page.ExportObject() in Page.cs: line 410
at Rock.Tests.CMS.PageTests.TheExportObjectMethod.ShouldCopyPropertiesOfDTO() in PageTests.cs: line 16
以下是来自 Rock.Data 命名空间的一些相关(带注释的)代码片段:
IRepository.cs
public interface IRepository<T> where T : class
{
// Very basic CRUD repository contract...
}
EFRepository.cs
public class EFRepository<T> where T : Model<T>
{
// Concrete implementation of IRepository<T> specific to Entity Framework 4.3
}
服务.cs
public class Service<T> where T : Model<T>
{
private readonly IRepository<T> _repository;
// Inside this constructor are my changes...
public Service() // : this(new EFRepository<T>())
{
// Instead of hard-coding the use of EFRepository here, I
// thought it might be worthwhile to add a call out to a
// factory method implementation.
var factory = new RepositoryFactory<T>();
_repository = factory.FindRepository();
}
// This constructor never really appears to be called.
// From my test code's entry point, there's no way for me to
// explicitly call this constructor, hence the factory implemenation.
public Service(IRepository<T> repository)
{
_repository = repository;
}
}
RepositoryFactory.cs
// Here's my quick/dirty factory method implementation to try to generically
// instantiate an IRepository of my choosing for testing purposes...
public class RepositoryFactory<T> where T : Model<T>
{
public IRepository<T> FindRepository()
{
var repositoryTypeSetting = ConfiguraitonManager.AppSettings["RepositoryType"];
if (string.IsNullOrEmpty(repositoryTypeSetting))
{
return new EFRepository<T>();
}
var settingArray = repositoryTypeSetting.Split(new[] { ',' });
// I'm aware that Trim() is superfluous here, but this will be part of a development
// framework, so I'm trying to take whitespace/developer error into account.
var className = settingArray[0].Trim();
var assemblyName = settingArray[1].Trim();
// I've tried with and without Unwrap(), the exception originates from Activator.CreateInstance()
return (IRepository<T>) Activator.CreateInstance(assemblyName, className).Unwrap();
}
}
这是我在单独的 Rock.Tests 项目中使用的一些假对象和测试代码片段......
FakeRepository.cs
// Basic fake/stub implementation
public class FakeRepository<T> : IRepository<T> where T : Model<T>
{
// Nothing here yet other than `throw new NotImplementedException()` for each method in the contract
// We never make it here...
}
PageTests.cs
// Very basic XUnit test example...
public class PageTests
{
public class TheExportMethod
{
[Fact]
public void ShouldNotBeEmpty()
{
var page = new Page { Name = "FooPage" };
var result = page.Export();
Assert.NotEmpty(result);
}
}
}
应用程序配置
<configuration>
<appSettings>
<clear/>
<add key="RepositoryType" value="Rock.Tests.Fakes.FakeRepository,Rock.Tests"/>
</appSettings>
</configuration>
希望这涵盖了它相当彻底。提前致谢!