虽然为OSS project工作做贡献,但我遇到了TypeLoadException。我正在创建一个接缝,开发人员可以注入自己的Repository类来删除对EF的具体依赖,这样我就可以隔离我的新代码并运行一些测试。
对于具有嵌套类型arg的类型运行Activator.CreateInstance()
似乎会在运行时创建它。我之前已经多次使用过这种模式,但这次不同之处在于我正在使用它来动态注入通用的Repository模式实现。问题似乎与那种类型的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
}
Service.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);
}
}
}
的App.config
<configuration>
<appSettings>
<clear/>
<add key="RepositoryType" value="Rock.Tests.Fakes.FakeRepository,Rock.Tests"/>
</appSettings>
</configuration>
希望这完全涵盖它。提前谢谢!
答案 0 :(得分:1)
看起来您正在尝试实例化一个开放的泛型类型,因为您的配置文件没有为FakeRepository<T>
指定泛型类型参数。你需要做更多的事情:
<add key="RepositoryType" value="Rock.Tests.Fakes.FakeRepository`1[[Some.ModelType,Some.ModelAssembly]],Rock.Tests"/>