我有以下主要方法。 LocalCabelTV和LocalDishTV课程是主要的应用程序。该计划运作良好。
我想将LocalCabelTV和LocalDishTV保存在单独的dll文件中。我想知道如何在运行时加载这些类?我明白我们不会使用switch但是for循环来查找在特定目录中实现IVideoSource接口的所有dll文件并加载那些...
需要知道如何动态加载dll并创建对象并使用他们的方法吗?
foreach (string dll in Directory.GetFiles("C:\DLLs\*.dll"))
{
Assembly assemb = Assembly.LoadFrom(dll);
??
}
以下工作正常:
static void Main(string[] args)
{
SmartTv myTv = new SmartTv();
Console.WriteLine("Select A source to get TV Guide and Play");
Console.WriteLine("1. Local Cable TV\n2. Local Dish TV");
ConsoleKeyInfo input = Console.ReadKey();
switch (input.KeyChar)
{
case '1':
myTv.VideoSource = new LocalCabelTv();
break;
case '2':
myTv.VideoSource = new LocalDishTv();
break;
}
Console.WriteLine();
myTv.ShowTvGuide();
myTv.PlayTV();
Console.ReadKey();
}
class SmartTv
{
IVideoSource currentVideoSource = null;
public IVideoSource VideoSource
{
get
{
return currentVideoSource;
}
set
{
currentVideoSource = value;
}
}
public void ShowTvGuide()
{
if (currentVideoSource != null)
{
Console.WriteLine(currentVideoSource.GetTvGuide());
}
else
{
Console.WriteLine("Please select a Video Source to get TV guide from");
}
}
public void PlayTV()
{
if (currentVideoSource != null)
{
Console.WriteLine(currentVideoSource.PlayVideo());
}
else
{
Console.WriteLine("Please select a Video Source to play");
}
}
class LocalCabelTv : IVideoSource
{
const string SOURCE_NAME = "Local Cabel TV";
string IVideoSource.GetTvGuide()
{
return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
}
string IVideoSource.PlayVideo()
{
return string.Format("Playing - {0}", SOURCE_NAME);
}
}
class LocalDishTv : IVideoSource
{
const string SOURCE_NAME = "Local DISH TV";
string IVideoSource.GetTvGuide()
{
return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
}
string IVideoSource.PlayVideo()
{
return string.Format("Playing - {0}", SOURCE_NAME);
}
}
答案 0 :(得分:1)
要在运行时加载此程序集并创建一个对象:
Assembly MyDALL = Assembly.Load("DALL"); // DALL is name of my dll
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // LoadClass is my class
object obj = Activator.CreateInstance(Type.GetType("DALL.LoadClass, DALL", true));
对于动态方法,您还可以使用动态方法。它比反射更快(此方法只需要Activator所需的1/10。)
以下是使用动态方法创建对象的示例代码。
void CreateMethod(ConstructorInfo target)
{
DynamicMethod dynamic = new DynamicMethod(string.Empty,
typeof(object),
new Type[0],
target.DeclaringType);
methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}
查看以下链接以获取更多信息:Load Assembly at runtime and create class instance
编辑:正如用户@taffer所提到的,DynamicMethod.CreateDelegate比反射慢得多。因此,只有在创建的委托被调用数百或数千次时,我才会使用它。使用具有缓存的Activator更快。其次,Activator对于无参数构造函数来说非常快,除非你实例化这么多类型,这使得内部小缓存无用。
答案 1 :(得分:1)
您需要使用所需类加载DLL并迭代其类型,而不是查找实现IVideoSource
并激活它们的那些:
public static IEnumerable<IVideoSource> GetVideoSources(List<string> assemblyPathes)
{
IEnumerable<Assembly> yourAssembliesWithClasses = assemblyPathes.Select(x => Assembly.Load(x));
IEnumerable<Type> implementingTypes = yourAssembliesWithClasses
.GetTypes()
.Where(x => x.IsAssignableFrom(IVideoSource));
return implementingTypes.Select(x => Activator.CreateInstance(x));
}
请注意,Activator.CreateInstance()
要求类型具有空构造函数,如果它们没有您可以使用的构造函数,则Type.GetUniGetUninitializedObject(Type type)
FormatterServices
初始化它们。