C# 使用泛型和后期绑定的反射。如何在运行时播放?
我试图在c#中使用带有反射的泛型来构建一个可以处理多个类的方法。我使用一个第三方DLL,它有一堆类,在这些类上,我调用了一个方法。它们都返回不同的返回类型,但一旦我得到对象,我会执行相同的处理(在下面的示例中,这将是区域A和区域B) 基本上,我想开发一个方法,将类名和预期返回类型作为泛型变量,然后调用正确的方法(methodName),该方法作为该方法的参数提供 下面的程序编译良好,运行无误,但问题是“area”变量的预期类型。在下面的语句中,第一行是类型casted to(TArea),如果我在Visual Studio中将鼠标悬停在它上面,intellisense会显示属性“name”,但键入区域。name不会给我该值。我必须键入((area)area).name 问题是类型“AreaA”在运行时可能是另一种类型。在本例中,“AreaB”这样我就可以硬编码一个cast 如何将“area”变量强制转换为适当的类型,以便查看第三方类的公共方法/属性 注意:在我的示例中,所有内容都在同一个类中,但实际上ServiceA、ServiceB、area和AreaB的定义将在第三方DLL中。 一如既往,提前感谢 图1-“area”变量只能在强制转换为“AreaA”时获得“name”属性。 图2-完成课程C# 使用泛型和后期绑定的反射。如何在运行时播放?,c#,generics,system.reflection,late-binding,C#,Generics,System.reflection,Late Binding,我试图在c#中使用带有反射的泛型来构建一个可以处理多个类的方法。我使用一个第三方DLL,它有一堆类,在这些类上,我调用了一个方法。它们都返回不同的返回类型,但一旦我得到对象,我会执行相同的处理(在下面的示例中,这将是区域A和区域B) 基本上,我想开发一个方法,将类名和预期返回类型作为泛型变量,然后调用正确的方法(methodName),该方法作为该方法的参数提供 下面的程序编译良好,运行无误,但问题是“area”变量的预期类型。在下面的语句中,第一行是类型casted to(TArea),如果我
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
运用系统反思;
使用System.IO;
名称空间反射示例
{
类样本
{
A类服务
{
公共整数大小{get;set;}
公共字符串名称{get;set;}
公共服务A()
{
name=“TestA”;
尺寸=100;
}
公共区域A doWork(字符串名称)
{
返回新区域A(名称);
}
}
A类区域
{
公共字符串名称{get;set;}
公共区域A(字符串名称)
{
this.name=名称;
}
公共区域a()
{
}
}
B类服务
{
公共整数大小{get;set;}
公共字符串名称{get;set;}
公共服务B()
{
name=“TestB”;
尺寸=50;
}
公共区域B doWork(字符串名称)
{
返回新区域B(名称);
}
}
B类地区
{
公共字符串名称{get;set;}
公共区域B(字符串名称)
{
this.name=名称;
}
公共区域B()
{
}
}
静态void Main(字符串[]参数)
{
runService(“doWork”);
}
私有静态void运行服务(string methodName)
其中TService:class,new()
其中TArea:class,new()
{
//编译时处理
类型areaType=类型(跗骨);
类型serviceType=typeof(t服务);
//打印完整的程序集名称和限定的程序集名称
Console.WriteLine(“AreaType—完整程序集名称:\t{0}.”,AreaType.assembly.FullName.ToString());//打印完整程序集名称。
Console.WriteLine(“AreaType--限定程序集名称:\t{0}.”,AreaType.AssemblyQualifiedName.ToString());//打印限定程序集名称。
Console.WriteLine(“ServiceType—完整程序集名称:\t{0}.”,ServiceType.assembly.FullName.ToString());//打印完整程序集名称。
Console.WriteLine(“ServiceType--限定程序集名称:\t{0}.”,ServiceType.AssemblyQualifiedName.ToString());//打印限定程序集名称。
//之所以这样做,是因为在我的代码中,程序集不在Executy程序集中,它只是作为引用设置的
var assembly=assembly.Load(serviceType.assembly.FullName);
//初始化通用区域
TArea面积=默认值(TArea);
//获取该服务的实例,以便稍后调用该方法
var instance=Activator.CreateInstance(serviceType);
//获取提供给runService方法的methodName的methodInfo
MethodInfo-dfpMethod=serviceType.GetMethod(methodName,BindingFlags.Public | BindingFlags.Instance);
//area是类型强制转换为(TArea),intellisense显示属性“name”,但键入area.name不会给出值
//我必须键入((AreaA)area).name。问题是类型“AreaA”可能是另一种类型。在本例中,“AreaB”
area=(TArea)dfpMethod.Invoke(实例,新对象[]{“Area123”});
AreaA AreaA=(AreaA)dfpMethod.Invoke(实例,新对象[]{“Area123”});
Console.WriteLine();
}
}
}
我认为您在这里遇到的问题是将动态加载的类型(Assembly.Load())与直接从项目引用的类型混合在一起,您可以在intellisense中看到这些类型,即AreaA
如果您使用反射动态加载整个程序集,intellisense将不会帮助您查看类成员,因为这些信息需要在编译时知道,并且根据定义,您是在运行时加载程序集
如果您只想查看类型可用的所有公共属性的列表,则可以使用以下选项:
var areaProperties = area.GetType().GetProperties();
但是,这一切都是在运行时完成的,所以对您没有帮助
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
namespace ReflectionExample
{
class Sample
{
class ServiceA
{
public int size {get; set;}
public string name {get; set;}
public ServiceA()
{
name = "TestA";
size = 100;
}
public AreaA doWork(string name)
{
return new AreaA(name);
}
}
class AreaA
{
public string name { get; set;}
public AreaA(string name)
{
this.name = name;
}
public AreaA()
{
}
}
class ServiceB
{
public int size { get; set; }
public string name { get; set; }
public ServiceB()
{
name = "TestB";
size = 50;
}
public AreaB doWork(string name)
{
return new AreaB(name);
}
}
class AreaB
{
public string name { get; set; }
public AreaB(string name)
{
this.name = name;
}
public AreaB()
{
}
}
static void Main(string[] args)
{
runService<ServiceA, AreaA>("doWork");
}
private static void runService<TService, TArea>(string methodName)
where TService : class, new()
where TArea : class, new()
{
//Compile time processing
Type areaType = typeof(TArea);
Type serviceType = typeof(TService);
//Print the full assembly name and qualified assembly name
Console.WriteLine("AreaType--Full assembly name:\t {0}.", areaType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("AreaType--Qualified assembly name:\t {0}.", areaType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
Console.WriteLine("ServiceType--Full assembly name:\t {0}.", serviceType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("ServiceType--Qualified assembly name:\t {0}.", serviceType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
//This is done because in my code, the assembly doesn't reside in the executiy assembly, it is only setup as a reference
var assembly = Assembly.Load(serviceType.Assembly.FullName);
//Initialize the generic area
TArea area = default(TArea);
//Get an instance of the service so I can invoke the method later on
var instance = Activator.CreateInstance(serviceType);
//Get the methodInfo for the methodName supplied to the runService method
MethodInfo dfpMethod = serviceType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
//area is type casted to (TArea), the intellisense shows the property 'name', but typing area.name doesn't give me the value
//I have to type ((AreaA)area).name. Problem is the type 'AreaA' could be another type. In this example, 'AreaB'
area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
AreaA areaa = (AreaA)dfpMethod.Invoke(instance, new object[] { "Area123" });
Console.WriteLine();
}
}
}
var areaProperties = area.GetType().GetProperties();
var nameValue = area.GetType().GetProperty("name").GetValue(area);
TArea area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
var area = (dynamic)dfpMethod.Invoke(instance, new object[] { "Area123" });
return area.name; // no error
public class MyGenericArea
{
public MyGenericArea(string name)
{
this.Name = name;
}
public string Name {get; set;}
}
var area = (dynamic)dfpMethod.Invoke(instance, new object[] { "Area123" });
return new MyGenericArea(area.name);