是否可以在没有main方法的情况下在C#中创建项目,并导入另一个具有main方法的项目,并将入口点设置为导入项目的main 方法?
这样做的目的是提供一个包含其主方法和所有启动代码的库,只需要几个"插件"方法。这将最大限度地减少样板(特别是启动(代码。
抽象示例:
考虑具有计划的项目 1.cs:
namespace Project1 {
public class Program {
public static void Main() {
Console.WriteLine("All your Main are belong to us");
Plugin pluginClass = MagicallyGetInstanceOfPluginClassProbablyThroughInjection();
pluginClass.DoSomethingSpecificDependingOnPluginClassDefinition();
}
private Plugin MagicallyGetInstanceOfPluginClassProbablyThroughInjection(){
/*...*/
}
}
public interface Plugin {
void DoSomethingSpecificDependingOnPluginClassDefinition();
}
}
现在考虑只有类 MyPlugin.cs 的项目 2:
namespace Project2 {
using Project1;
public class MyPlugin: Plugin {
public void DoSomethingSpecificDependingOnPluginClassDefinition() {
Console.WriteLine("I'm doing something specific!");
}
}
}
需要指出的事项:
- 项目 1 只是一个库,可能是 nuget's
- 导入项目 1 的是项目 2,而不是相反
- 上面的 MyPlugin.cs 类是项目中唯一的类/文件(不包括清单、应用程序配置等(
目的:
项目2 应该编译成可执行文件,运行项目 1 的 Main 函数,而无需编写更多代码(没有样板启动/设置代码(。然后可以有项目 3、4、5、...它们都实现了特定于插件的代码,导入项目 1 并作为独立实例运行。
这可能做到吗?还是我仍然必须在每个项目中创建一个 main 方法来调用导入项目的启动代码?提前非常感谢!
您可以创建一个插件容器,用于扫描目录中的程序集并尝试加载它们。为此,您需要一个共享接口(您的程序和插件已知的接口。
然后,您可以将 DLL 添加到定义的插件目录中,或者您可以在主运行项目中引用项目。
接口的示例可以是:
public interface IStandAlone
{
void Run();
}
和 1 或简单的实现可能是
public class Program1 : IStandAlone
{
public void Run()
{
Console.WriteLine("Program1");
}
}
public class Program2 : IStandAlone
{
public void Run()
{
Console.WriteLine("Program 2");
}
}
然后,您需要从当前程序集加载可能的程序集(如此示例中所做的那样(,或者通过扫描目录中可能具有你的类型的 dll 来加载可能的程序集。
扫描当前程序集以查找确定类型的任何实现的示例:
public class PluginContainer<T>
{
Type targetType = typeof(T);
public virtual IList<Type> GetMatchingTypes()
{
Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
IList<Type> items = new List<Type>();
if (currentAssemblies == null || currentAssemblies.Length == 0)
{
Console.WriteLine("No assemblies found!");
return items;
}
foreach (Assembly ass in currentAssemblies)
{
try
{
var types = ass.GetTypes();
foreach (var t in types)
{
if (t.IsInterface)
{
continue;
}
if (!(targetType.IsAssignableFrom(t)))
{
continue;
}
items.Add(t);
}
}
catch (ReflectionTypeLoadException rtle)
{
/* In case the loading failed, scan the types that it was able to load */
Console.WriteLine(rtle.Message);
if (rtle.Types != null)
{
foreach (var t in rtle.Types)
{
if (t.IsInterface)
{
continue;
}
if (!(targetType.IsAssignableFrom(t)))
{
continue;
}
items.Add(t);
}
}
}
catch (Exception ex)
{
/* General exception */
Console.WriteLine(ex.Message);
}
}
return items;
}
public IList<T> GetPlugins()
{
IList<Type> matchingTypes = GetMatchingTypes();
IList<T> items = new List<T>();
if (matchingTypes == null || matchingTypes.Count == 0)
{
Console.WriteLine("No matching types of {0} found", typeof(T).FullName);
return null;
}
foreach (Type type in matchingTypes)
{
try
{
T nObj = (T)Activator.CreateInstance(type);
items.Add(nObj);
}
catch (Exception ex)
{
Console.WriteLine("Error occured trying to run {0}rn{1}", type.FullName, ex.Message);
}
}
return items;
}
}
然后可以在 main 方法中使用它来扫描任何可用的插件,并执行它们:
static void Main(string[] args)
{
PluginContainer<IStandAlone> container = new PluginContainer<IStandAlone>();
var plugins = container.GetPlugins();
foreach (var plugin in plugins)
{
plugin.Run();
}
Console.ReadLine();
}
最终作为输出给出:
Program1
Program 2
请记住,这是一个非常基本的例子,应该有一个经过深思熟虑的界面,它实际上只包含基础知识,并且可能会给运行插件的程序一些反馈(尽管这不应该是一个必需的(。还提供插件版本,也许是更新 URL,如果您的插件可以由第三方提供商维护或实现,这些东西可能会很方便......
我相信启动方法的要求是它的签名需要public static void
并且需要具有单个string[]
参数。它可能还需要命名为"主要",但我对此表示怀疑。如果方法符合这些要求,则应可在项目属性中选择该方法作为启动方法。
但是,启动方法是用于在启动独立可执行程序时运行该程序的方法。我相信您正在寻找的更多的是插件架构。您可以创建一个属性,并使用该属性标记入口点方法。然后,在服务中,您需要反映正在加载的插件程序集中的类,并找到标有自定义属性的方法,并调用相应的方法。
抱歉,如果这听起来有点模糊,但"插件架构"并不是一个微不足道的话题。
另一种方法是使用 System.Diagnostics.Process.Start(string)
方法将您的"插件"作为独立程序启动。
我不太确定你要什么。每个 C# 项目要么是.exe
,要么是.dll
。.dll
没有主方法,但.exe
需要一个。这是描述它应该是什么样子的链接。
如果您有许多非常相似的应用程序,那么您可以在.dll
项目中移动所有常见内容,并在所有应用程序中引用它。然后,您可以从每个.exe
调用方法。在每个.exe
中,您仍然会有一个Main()
方法,但它只包含一行调用公共实现。
或者你可以做一些类似插件架构的事情,你有一个.exe
,所有其他应用程序都是.dll
项目,这些项目由.exe
根据需要加载和执行。
六个一个,六个另一个,最后都是一样的。