且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用具有更好性能的反射调用方法

更新时间:2023-09-13 15:15:16

首先不要使用反射,除非你需要它并且你知道你在做什么,所以如果你的方法计数很低使用switch语句:

  switch (comm.Method)
{
case method1 this .Method1(comm.Data); break ;
... // 依此类推
}

您还可以使用预先填充的方法处理程序委托使用字典<字符串,操作>



如果你真的需要使用反射,那么你应该首先找出代码的位置很慢,然后使用 Dictionary $开始缓存 Delegate.CreateDelegate c $ c>更快查询:



加速反射调用C#/ .NET - 堆栈溢出 [ ^ ]


扩展Mehdi Gholam的解决方案,以下是方法 ProcessFileType 发现需要转换的数据类型,查找数据类型,然后执行转换来自JSON字符串并返回特定类型的类结构。

  //  只有一些类型是简要列表 
private readonly 字典<字符串,Func< JObject,文件>> mimeTypes
= new Dictionary< string,Func< JObject,File>>
{
{ application / vnd.google-apps.folder,转换< Folder>()},
{ image / jpeg,转换< JpgImage&gt ;()},
{ image / png,转换< PngImage>() },
{ application / zip,转换< Zipped>()},
{ application / x-zip-compressed,转换< Zipped>()},
{ video / mp4,转换< Mp4Video>()},
{ text / plain,转换< TxtDocument>()},
{ application / vnd.openxmlformats-officedoc ument.presentationml.presentation
转换< PptDocument>()},
{ application / vnd.openxmlformats-officedocument.wordprocessingml.document
转换< WordDocument>()}
};

// 转换类型的文件.... mimeTypes
private void ProcessFileType(List< File> results,IList< JObject> jObjs, int i)
{
var fileToken = jObjs [i] .FindTokens( mimeType);
if (fileToken!= null && fileToken.Count > 0
{
var key = mimeTypes.Keys.FirstOrDefault(x = > x.Equals(fileToken [ 0 ]。的ToString()));
if (key!= null
{
results。添加(MIMETYPES [键](jObjs [I]));
}
}
}

// 转换Json将对象数据转换为指定的类类型
private static Func< JObject,文件>转换< TModel>()其中 TModel:文件
{
return (jObj )= > JsonHelper.ToClass< TModel>(jObj.ToString());
}



要使用Reflection执行完全相同的操作,它看起来像这样:

  public  JsonDataTypeConverter()
{
if (convert == null )
convert = GetType()。GetMethod( nameof (转换),
BindingFlags.Instance | BindingFlags.NonPublic);
}

private static MethodInfo convert; // 在类实例化时配置

// 只有一些类型是简要列表
private static readonly 字典<字符串,类型> mimeTypes = new 字典<字符串,类型>
{
{ application / vnd.google-apps.folder typeof (文件夹)},
{ image / jpeg typeof (JpgImage)},
{ image / png, typeof (PngImage)},
{ application / zip typeof (Zipped)},
{ application / x-zip-compressed typeof (Zipped)},
{ video / mp4, typeof (Mp4Video)},
{ text /纯 typeof (TxtDocument)},
{ application / vnd.openxmlformats-officedocument.presentationml.presentation
typeof (PptDocument)},
{ application / vnd.openxmlformats-officedocument.wordprocessingml.document
typeof (WordDocument)}
};

// 转换类型的文件.... mimeTypes
private void ProcessFileType(List< File> results,IList< JObject> jObjs, int i)
{
var fileToken = jObjs [i] .FindTokens( mimeType);
if (fileToken!= null && fileToken.Count > 0
{
var key = mimeTypes.Keys.FirstOrDefault(x = > x.Equals(fileToken [ 0 ]。的ToString()));
if (key!= null
{
var method = convert.MakeGenericMethod( new [] {m​​imeTypes [key]});
var data = method.Invoke( this new [] {jObjs [i]});
results.Add((File)data);
}
}
}

// 转换Json将对象数据转换为指定的类类型
private TModel转换< TModel>(JObject jObj)其中 TModel:IResourceKind
{
return JsonHelper.ToClass< TModel>(jObj.ToString());
}



如果您想查看代码的实际应用,可以从本文下载:在C#中使用JSON& VB [ ^ ](Google云端硬盘 - 文件资源管理器示例)


I am using the Invoke method to call method using reflection. Performance of this not great. Is there any other solution

What I have tried:

void ExecuteMethodViaReflection(TestObj comm)
{
    var paramNames = comm.paramNames; //of type string array
    var paramData = comm.Data; //of type Object array

    Type t = this.GetType();
    t.InvokeMember(comm.Method, BindingFlags.InvokeMethod, null, this, paramData, null, null, paramNames);
    }

First don't use reflection unless you need it and you know what you are doing, so if your method counts is low use a switch statement:
switch(comm.Method)
{
    case "method1" : this.Method1(comm.Data); break;
    ...// and so on
}

You can also use a Dictionary<string, Action> with pre-populated method handler delegates.

If you really need to use reflection then you should first find out where you code is slow then start caching the Delegate.CreateDelegate using a Dictionary for faster lookup:

Speeding up Reflection Invoke C#/.NET - Stack Overflow[^]


Expanding on Mehdi Gholam's solution, here is a real-life example of where the method ProcessFileType "discovers" the type of data that it needs to convert to, looks up the type of data, then executes the conversion from JSON string and returns a class structure of a specific type.
// only some types are lists for briefity
private readonly Dictionary<string, Func<JObject, File>> mimeTypes
    = new Dictionary<string, Func<JObject, File>>
{
    { "application/vnd.google-apps.folder", Convert<Folder>() },
    { "image/jpeg", Convert<JpgImage>() },
    { "image/png", Convert<PngImage>() },
    { "application/zip", Convert<Zipped>() },
    { "application/x-zip-compressed", Convert<Zipped>() },
    { "video/mp4", Convert<Mp4Video>() },
    { "text/plain", Convert<TxtDocument>() },
    { "application/vnd.openxmlformats-officedocument.presentationml.presentation",
      Convert<PptDocument>() },
    { "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      Convert<WordDocument>() }
};

// Convert file of type.... mimeTypes
private void ProcessFileType(List<File> results, IList<JObject> jObjs, int i)
{
    var fileToken = jObjs[i].FindTokens("mimeType");
    if (fileToken != null && fileToken.Count > 0)
    {
        var key = mimeTypes.Keys.FirstOrDefault(x => x.Equals(fileToken[0].ToString()));
        if (key != null)
        {
            results.Add(mimeTypes[key](jObjs[i]));
        }
    }
}

// Convert Json Object data into a specified class type
private static Func<JObject, File> Convert<TModel>() where TModel : File
{
    return (jObj) => JsonHelper.ToClass<TModel>(jObj.ToString());
}


To do exactly the same thing slower using Reflection, it would look something like this:

public JsonDataTypeConverter()
{
    if (convert == null)
        convert = GetType().GetMethod(nameof(Convert),
                                      BindingFlags.Instance | BindingFlags.NonPublic);
}

private static MethodInfo convert; // configured on class instantiation

// only some types are lists for briefity
private static readonly Dictionary<string, Type> mimeTypes = new Dictionary<string, Type>
{
    { "application/vnd.google-apps.folder", typeof(Folder) },
    { "image/jpeg", typeof(JpgImage) },
    { "image/png", typeof(PngImage) },
    { "application/zip", typeof(Zipped) },
    { "application/x-zip-compressed", typeof(Zipped) },
    { "video/mp4", typeof(Mp4Video) },
    { "text/plain", typeof(TxtDocument) },
    { "application/vnd.openxmlformats-officedocument.presentationml.presentation",
      typeof(PptDocument) },
    { "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      typeof(WordDocument) }
};

// Convert file of type.... mimeTypes
private void ProcessFileType(List<File> results, IList<JObject> jObjs, int i)
{
    var fileToken = jObjs[i].FindTokens("mimeType");
    if (fileToken != null && fileToken.Count > 0)
    {
        var key = mimeTypes.Keys.FirstOrDefault(x => x.Equals(fileToken[0].ToString()));
        if (key != null)
        {
            var method = convert.MakeGenericMethod(new[] { mimeTypes[key] });
            var data = method.Invoke(this, new[] { jObjs[i] });
            results.Add((File)data);
        }
    }
}

// Convert Json Object data into a specified class type
private TModel Convert<TModel>(JObject jObj) where TModel : IResourceKind
{
    return JsonHelper.ToClass<TModel>(jObj.ToString());
}


If you want to see the code in action, you can download it from this article: Working with JSON in C# & VB[^] (Google Drive - File Explorer example)