У вас есть проблема с дизайном. У вас есть сборка (назовем ее сборкой А), содержащей код отражения образца, который вы опубликовали. У вас также есть вторая сборка (назовем ее сборкой B), которая содержит MyClass и Test.
Проблема в том, что в коде отражения вы пытаетесь создать экземпляр класса Test, чтобы передать его в качестве параметра MyClass.MyFunction.
Вы упомянули, что вы скопировали исходный код для класса Test в сборку A; это не будет работать. То, что вы там сделали, по существу, создает два разных класса с одинаковым именем и одинаковой структурой. Поскольку два класса не совпадают с CLR, вы получите недопустимое исключение литых, если попытаетесь отбросить один на другой.
Учитывая то, что вы опубликовали до сих пор, мне кажется, что наиболее простым решением для вашего подхода является наличие третьей сборки (назовем ее сборкой C), которая содержит компоненты, которые известны обеим сборкам A и B ,Создайте проект библиотеки классов в своем решении, переместите класс Test в этот проект, избавитесь от любых других событий класса Test в первых двух проектах и добавьте ссылки в оба первых двух проекта, ссылающихся на новый проект. Как только вы это сделаете, как сборка A, так и сборка B будут ссылаться на одно и то же определение класса для класса Test, и пример кода, который вы опубликовали, будет работать.
Позвольте мне указать на что-то. Если код в сборке A не знает достаточно о коде в сборке B, чтобы создать экземпляр MyClass и напрямую вызвать MyFunction (а не через отражение), то как он знает об этом коде, чтобы узнать, какие параметры должны пройти? Есть ли в MyFunction общая сигнатура метода, которую понимает сборка A? Если это так, то MyClass, вероятно, следует реализовать интерфейс, что узел А знает, так что сборка А может вызвать MyFunction непосредственно, как показано ниже:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
IMyInterface instance = Activator.CreateInstance(dllType) as IMyInterface;
if (instance != null) // check if this object actually implements the IMyInterface interface
{
instance.MyFunction(objTest);
}
}
Если это не похоже, подход, который вы хотите, то есть другие варианты. Поскольку, похоже, вы не хотите, чтобы сборка A имела прямую ссылку на сборку B, если вы сохраняете класс Test внутри сборки B, то нет никакой возможности для сборки A иметь какие-либо знания класса Test для его построения. В этом случае вы можете использовать подход с заводскими шаблонами, в основном, чтобы сборка А знала какой-то заводский объект, способный создавать экземпляр объекта Test. Ниже приведен пример реализации:
Я уже упоминал о создании третьего проекта. Я бы по-прежнему рекомендовал это сделать. В моем примере я назвал свой «MyProject.Common». Он содержит следующий код:
// define a simple factory interface
public interface IFactory
{
object CreateInstance();
}
// and a generic one (hey, why not?)
public interface IFactory<T> : IFactory
{
new T CreateInstance();
}
// define a Factory attribute that will be used to identify the concrete implementation of a factory
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class FactoryAttribute : Attribute
{
public Type FactoryType { get; set; }
public FactoryAttribute(Type factoryType)
{
this.FactoryType = factoryType;
}
}
The IFactory интерфейсы и будет известно и понятно другими проектами в моем решении атрибута Factory, так как оба они ссылаются на проекте MyProject.Common.
Ниже приведен код, содержащийся в моем проекте «MyProject.Components»:
public class Test
{
public string Name { get; set; }
public string Type { get; set; }
public Test(string name, string type)
{
this.Name = name;
this.Type = type;
}
}
public class TestFactory : IFactory<Test>
{
#region IFactory<Test> Members
public Test CreateInstance()
{
return new Test("name", "type");
}
#endregion
#region IFactory Members
object IFactory.CreateInstance()
{
return this.CreateInstance();
}
#endregion
}
public class MyClass
{
// the Factory attribute on the first parameter indicates that the class TestFactory
// should be used as a factory object to construct the argument for this method
public string MyFunction([Factory(typeof(TestFactory))]Test obj)
{
if (obj == null)
return null;
else
return obj.ToString();
}
}
Наконец, я заменил оригинальный код отражения, который Вы отправляли сообщение со следующим:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
// use the parameter information to construct the arguments
ParameterInfo[] parameters = m.GetParameters();
object[] args;
if (parameters != null && parameters.Length > 0)
{
args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
// check for factory attributes on the actual parameter
FactoryAttribute[] attributes = parameters[i].GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found, check the parameter type for factory attributes
if (attributes == null || attributes.Length == 0)
attributes = parameters[i].ParameterType.GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found still, then give up
if (attributes == null || attributes.Length == 0)
{
// this parameter has no factory specified,
// so how would this code know how to create the argument for that parameter ???
args[i] = null;
continue; // move on to the next parameter
}
// there should only be one factory attribute, so use the first one
// assumption made here is that all factory classes will have a parameterless constructor
IFactory factory = Activator.CreateInstance(attributes[0].FactoryType) as IFactory;
args[i] = factory.CreateInstance();
}
}
else
// there are no parameters
args = null;
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
Пожалуйста, включите подпись метода, которую вы пытаетесь вызвать ('MyFunction' специально, из' dllType.GetMethod («MyFunction»); '). Кроме того, где происходит исключение? – Femaref