是否可以在不引用其所在项目的情况下调用方法?

时间:2019-06-13 09:46:59

标签: c#

我有两个项目:引擎,客户端。在执行Engine1.cs类的过程中,我想通过将来自Engine.cs的对象传递给ClientAction类来打开Windows窗体。客户端引用了Engine项目。

namespace Engine {

   public Class Engine1 {
     public Engine1() {
      }

//what I would do if I could reference the Client project
     ClientAction.OpenForm(obj1, obj2);
   }
}

using Engine;

namespace Client { 

   public Class ClientAction {

     public ClientAction() { }

      public OpenForm(object obj1, object obj2) {

         Form1.Open(obj1, obj2){
            ...
         }
      }
   }
}

4 个答案:

答案 0 :(得分:1)

您可以使用反射和类System.Activator(“ mscorlib.dll”程序集)来完成此操作。如下定义类:

在项目 Engine

using System;
using System.Reflection;

namespace Engine
{
    public class Engine1
    {
        public Engine1()
        {
            var clientAction = Activator.CreateInstance(
                Type.GetType("Client.ClientAction, Client"), new object[] { });
            MethodInfo methodInfo = clientAction.GetType().GetMethod("OpenForm");
            var arg1 = new object();
            var arg2 = new object();
            methodInfo.Invoke(clientAction, new object[] { arg1, arg2 });
        }
    }
}

在项目 Client 中, 类ClientAction

namespace Client
{
    public class ClientAction
    {
        public ClientAction() { }

        public void OpenForm(object obj1, object obj2)
        {
            new Form1()
            {
                Text = "OpenForm(object obj1, object obj2)"
            }.Show();
        }
    }
}

现在在项目 Client 中,您可以像这样在类Program中对其进行测试:

using System;
using System.Windows.Forms;

namespace Client
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var engine1 = new Engine.Engine1();
            Application.Run(new Form1());
        }
    }
}

另一种选择是使用委托。您必须在项目 Engine 中创建一个静态事件,并在项目 Client 中为该事件订阅一个处理程序,该处理程序将调用所需的方法。

在项目 Engine

代表:

namespace Engine
{
    public class OpenFormEventArgs
    {
        public object Obj1 { get; set; }
        public object Obj2 { get; set; }
    }

    public delegate void OpenFormEventHandler(object sender, OpenFormEventArgs e);
}

Engine1

namespace Engine
{
    public class Engine1
    {
        public static event OpenFormEventHandler OpenForm;

        public Engine1()
        {
            var obj1 = new object();
            var obj2 = new object();
            OpenFormEventArgs e = new OpenFormEventArgs() { Obj1 = obj1, Obj2 = obj2 };
            OpenForm?.Invoke(this, e);
        }
    }
}

在项目 Client 中, 类ClientAction

namespace Client
{
    public class ClientAction
    {
        public ClientAction()
        {
            Engine.Engine1.OpenForm += Engine1_OpenForm;
        }

        private void Engine1_OpenForm(object sender, Engine.OpenFormEventArgs e)
        {
            OpenForm(e.Obj1, e.Obj2);
        }

        public void OpenForm(object obj1, object obj2)
        {
            new Form1()
            {
                Text = "OpenForm(object obj1, object obj2)"
            }.Show();
        }
    }
}

现在在项目 Client 中,您可以像这样在类Program中对其进行测试:

using System;
using System.Windows.Forms;

namespace Client
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var clientAction = new ClientAction();
            var engine1 = new Engine.Engine1();
            Application.Run(new Form1());
        }
    }
}

答案 1 :(得分:0)

您可以在Engine项目中定义一个接口,其中包含用于调用各种操作的方法。客户端创建引擎时,使引擎需要该接口的实例。然后,实现该接口的客户端项目将处理事件,即创建表单。

另一种方法是公开Engine1类中的C#事件。在客户端中订阅这些事件,创建表单。

在两种方法中,由Engine类引发的事件都将在引用的Client项目中进行处理。

当项目紧密耦合时,或者要将值返回给引擎时(C#事件支持多个订阅者,并且订阅是可选的),接口会更好。

答案 2 :(得分:0)

为要传递给客户端的类型创建接口。在客户端项目中找到这些接口。

这样,您只需要从引擎到客户端的一个引用。接口的实现在Engine项目中很简单。

您可以从Engine调用客户端,并传递客户端所需的对象。

这带来了多项改进。您可以实现不同的引擎。客户不需要知道引擎如何工作。而且通常是更清洁,更灵活的设计。

注意:类和接口都应该在自己的文件中。


引擎

using Client;

namespace Engine
{
    public class Engine1
    {
        public Engine1()
        {
            var myObject = new MyObject
            {
                SomeProperty = null
            };

            ClientAction.OpenForm(myObject);
        }
    }

    public class MyObject : IMyObject
    {
        public object SomeProperty { get; set; }

        public void DoSomething()
        {
            // do something
        }
    }
}

客户

namespace Client
{
    public class ClientAction
    {
        public ClientAction() { }

        public OpenForm(IMyObject myObject)
        {
            myObject.DoSomething();
            Form1.Open(myObject.SomeProperty);
        }
    }

    public interface IMyObject
    {
        object SomeProperty { get; set; }
        void DoSomething();
    }
}

答案 3 :(得分:-1)

不,这是不可能的,这表明开发人员的设计选择不正确。

在两个项目/应用程序甚至库之间共享的代码应该在它们自己的单独项目中。通常称为“普通”。

实质上,您将具有以下结构:

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "temperature_x": 2,
    "temperature_y": 2,
    "temperature_z": 0,
    "timestamp": 1.553168075444e+12
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "temperature_x": 2,
    "timestamp": 1.553168075444e+12,
    "vibration_x": 21,
    "vibration_z": 10
  }
]

在此结构中,Project1和Project2可以引用Common并使用相同的代码库。

您应该注意的另一件事是潜在的circular dependencies,例如,如果 ...\MySolution\ Project1\ ... Project2\ ... Common\ CommonClass.cs 中的类依赖于Project1中的类,而Common中的类可能会发生Common依赖于Project1中的类。