У вас небольшая проблема с дизайном.У вас есть сборка (назовем ее сборкой A), содержащая пример кода отражения, который вы опубликовали.У вас также есть вторая сборка (назовем ее сборкой B), которая содержит MyClass и Test.
Проблема в том, что в вашем коде отражения вы пытаетесь создать экземпляр класса Test, чтобы вы могли передать егов качестве параметра MyClass.MyFunction.
Вы упомянули, что скопировали исходный код класса Test в сборку A;это не будет работать.По сути, вы создали два разных класса с одинаковыми именами и одинаковой структурой.Поскольку эти два класса не совпадают в том, что касается CLR, вы получите недопустимое исключение приведения, если попытаетесь привести один к другому.
Учитывая то, что вы опубликовали, кажется,Для меня самое простое решение для вашего подхода - это иметь третью сборку (назовем ее сборкой C), которая содержит компоненты, которые известны обеим сборкам A и B. Создайте проект библиотеки классов в своем решении, переместите класс Test вэтот проект, избавьтесь от любых других вхождений класса Test в первых двух проектах и добавьте ссылки в оба первых проекта, ссылающиеся на новый проект.Как только вы это сделаете, сборка A и сборка B будут ссылаться на одно и то же определение класса для класса Test, и пример кода, который вы опубликовали, будет работать.
Однако позвольте мне кое-что указать.Если код в сборке A не знает достаточно о коде в сборке B, чтобы создать экземпляр MyClass и вызвать MyFunction напрямую (а не через отражение), то как он узнает достаточно об этом коде, чтобы знать, какие параметры передать?Есть ли у MyFunction общая сигнатура метода, которую понимает сборка A?В этом случае MyClass, вероятно, должен реализовать интерфейс, о котором знает сборка A, чтобы сборка A могла напрямую вызывать 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.для того, чтобы построить один.В этом случае вы могли бы использовать подход фабричного шаблона, в основном так, чтобы сборка A знала о каком-то фабричном объекте, который способен создавать экземпляр объекта 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;
}
}
Интерфейсы 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);
}
}