今天来讲解反射的应用:

一、反射是什么?

简诉一下,反射就是.Net Framework 的一个帮助类库,可以获取并使用metadata(元数据清单);说的通俗易懂点,就是不用通过引用,仍然可以使用其他层的类。

二、让我们建一个项目来开始操作吧!!!

1、建立一个控制台应用程序,并建立一个类库,类库里添加一个用户类。

public class UsersInfo
{
public string Name { get; set; }
public bool Sex { get; set; }
public void CommonMethod()
{
Console.WriteLine("我是普通方法");
}
public void ParameterMethod(string name)
{
Console.WriteLine("我是带参数方法,我叫"+name);
} public void OverrideMethod(int age)
{
Console.WriteLine("我是重载方法,我今年"+age);
}
public void OverrideMethod(string name)
{
Console.WriteLine("我是重载方法,我叫" + name);
}
public void GenericityMethod<T>(T t)
{
Console.WriteLine("我是泛型方法方法,类型是"+typeof(T));
}
private void PrivateMethod()
{
Console.WriteLine("我是私有方法");
}
public static void StaticMethod()
{
Console.WriteLine("我是静态方法");
}
}

2、利用反射获取类库,和类

  • 第一步引用命名空间
  • 第二步,动态加载类库,写要获取类库的绝对路径
  • 第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name); }
}
}
}

3、利用反射获取属性,和属性类型

  • 遍历类型的属性集合
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
}
} }
}
}

三、获取方法(方法类型比较多,所以单独做个模块来写)

  • 创建一个符合类型的对象
  • 指定要获取的方法名称
  • 创建方法,第一个参数,对象,第二个参数,没有则为空

1、获取普通方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
}
Console.WriteLine("***********************普通方法*****************************");
object oUser = Activator.CreateInstance(type);//创建一个符合类型的对象
MethodInfo method = type.GetMethod("CommonMethod");//指定要获取的方法名称
method.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,没有则为空
} }
}
}

2、获取带参数的方法

  • 指定要获取的方法名称
  • 创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
} Console.WriteLine("***********************普通方法*****************************");
object oUser = Activator.CreateInstance(type);//创建一个符合类型的对象
MethodInfo commonMethod = type.GetMethod("CommonMethod");//指定要获取的方法名称
commonMethod.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,没有则为空 Console.WriteLine("***********************带参数的方法*****************************");
MethodInfo parameterMethod = type.GetMethod("ParameterMethod");//指定要获取的方法名称
parameterMethod.Invoke(oUser, new object[] { "餐餐"});//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
} }
}
}

3、重载方法

  • 指定要获取的方法名称,和参数类型
  • 创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
} Console.WriteLine("***********************普通方法*****************************");
object oUser = Activator.CreateInstance(type);//创建一个符合类型的对象
MethodInfo commonMethod = type.GetMethod("CommonMethod");//指定要获取的方法名称
commonMethod.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,没有则为空 Console.WriteLine("***********************带参数的方法*****************************");
MethodInfo parameterMethod = type.GetMethod("ParameterMethod");//指定要获取的方法名称
parameterMethod.Invoke(oUser, new object[] { "餐餐"});//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法int参数*****************************");
MethodInfo overrideMethodInt = type.GetMethod("OverrideMethod",new Type[] { typeof(int)});//指定要获取的方法名称,和参数类型
overrideMethodInt.Invoke(oUser, new object[] { 18 });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法string参数*****************************");
MethodInfo overrideMethodStrint = type.GetMethod("OverrideMethod", new Type[] { typeof(string) });//指定要获取的方法名称,和参数类型
overrideMethodStrint.Invoke(oUser, new object[] { "餐餐" });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
} }
}
}

4、泛型方法

  • 指定要获取的方法名称,和泛型参数类型
  • 创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
} Console.WriteLine("***********************普通方法*****************************");
object oUser = Activator.CreateInstance(type);//创建一个符合类型的对象
MethodInfo commonMethod = type.GetMethod("CommonMethod");//指定要获取的方法名称
commonMethod.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,没有则为空 Console.WriteLine("***********************带参数的方法*****************************");
MethodInfo parameterMethod = type.GetMethod("ParameterMethod");//指定要获取的方法名称
parameterMethod.Invoke(oUser, new object[] { "餐餐"});//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法int参数*****************************");
MethodInfo overrideMethodInt = type.GetMethod("OverrideMethod",new Type[] { typeof(int)});//指定要获取的方法名称,和参数类型
overrideMethodInt.Invoke(oUser, new object[] { 18 });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法string参数*****************************");
MethodInfo overrideMethodStrint = type.GetMethod("OverrideMethod", new Type[] { typeof(string) });//指定要获取的方法名称,和参数类型
overrideMethodStrint.Invoke(oUser, new object[] { "餐餐" });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************泛型方法*****************************");
MethodInfo genericityMethod = type.GetMethod("GenericityMethod").MakeGenericMethod(new Type[] {typeof(int)});//指定要获取的方法名称,和泛型参数类型
genericityMethod.Invoke(oUser, new object[] { 123 });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
} }
}
}

5、私有方法

  • 指定要获取的方法名称,指明是父类的私有方法
  • 创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;//第一步引用命名空间
namespace Reflection
{
class Program
{
static void Main(string[] args)
{
{
Console.WriteLine("***********************获取类*****************************");
//第二步,动态加载类库,写要获取类库的绝对路径
Assembly assembly= Assembly.LoadFile(@"C:\Users\炸天张缺缺\Desktop\Reflection\Reflection.Model\bin\Debug\Reflection.Model.dll");
//第三步,动态获取类型,写类库的名称和类的名称,不需要后缀
Type type = assembly.GetType("Reflection.Model.UsersInfo");
Console.WriteLine(type.Name);
Console.WriteLine("***********************获取属性*****************************");
//遍历类型的属性集合
foreach (var item in type.GetProperties())
{
Console.WriteLine(item.Name+" "+item.PropertyType);
} Console.WriteLine("***********************普通方法*****************************");
object oUser = Activator.CreateInstance(type);//创建一个符合类型的对象
MethodInfo commonMethod = type.GetMethod("CommonMethod");//指定要获取的方法名称
commonMethod.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,没有则为空 Console.WriteLine("***********************带参数的方法*****************************");
MethodInfo parameterMethod = type.GetMethod("ParameterMethod");//指定要获取的方法名称
parameterMethod.Invoke(oUser, new object[] { "餐餐"});//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法int参数*****************************");
MethodInfo overrideMethodInt = type.GetMethod("OverrideMethod",new Type[] { typeof(int)});//指定要获取的方法名称,和参数类型
overrideMethodInt.Invoke(oUser, new object[] { 18 });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************重载方法string参数*****************************");
MethodInfo overrideMethodStrint = type.GetMethod("OverrideMethod", new Type[] { typeof(string) });//指定要获取的方法名称,和参数类型
overrideMethodStrint.Invoke(oUser, new object[] { "餐餐" });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************泛型方法*****************************");
MethodInfo genericityMethod = type.GetMethod("GenericityMethod").MakeGenericMethod(new Type[] {typeof(int)});//指定要获取的方法名称,和泛型参数类型
genericityMethod.Invoke(oUser, new object[] { 123 });//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型 Console.WriteLine("***********************泛型方法*****************************");
MethodInfo privateMethod = type.GetMethod("PrivateMethod",BindingFlags.Instance|BindingFlags.NonPublic);//指定要获取的方法名称,指明是父类的私有方法
privateMethod.Invoke(oUser,null);//创建方法,第一个参数,对象,第二个参数,是一个object对象数组,写对应的参数类型
} }
}
}

6、静态方法

 Console.WriteLine("***********************静态方法*****************************");
MethodInfo staticMethod = type.GetMethod("StaticMethod");//指定要获取的方法名称
staticMethod.Invoke(null, null);//不需要实例化,所以第一个可以不写,为空

四、小扩展,反射书写ORM(请原谅我没有注释)

接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace NineMonthExam.IDAL
{
public interface IEFHelpers<T> where T:class
{
bool Add(T t);
bool Remove(int id);
bool Edit(T t);
List<T> GetAll();
}
}

dbhelp类

using NineMonthExam.IDAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data.SqlClient;
using NineMonthExam.Model; namespace NineMonthExam.DAL
{
public class DBHelpers<T> : IEFHelpers<T> where T : BaseModel
{
private static Type type;
private static string typeName;
private static string nameStr;
private static string noIdNameStr;
private static string sql = "";
private static StringBuilder addStr = new StringBuilder();
private static StringBuilder getStr = new StringBuilder();
private static StringBuilder removeStr = new StringBuilder();
private static StringBuilder modify = new StringBuilder();
private static StringBuilder modifyStr = new StringBuilder();
private static string conStr=ConfigurationManager.ConnectionStrings["conStr"].ConnectionString;
static DBHelpers()
{
type = typeof(T);
typeName = type.Name;
nameStr =string.Join(",", type.GetProperties().Select(m=>m.Name));
noIdNameStr = string.Join(",", type.GetProperties().Where(m=>!m.Name.Equals("Id")).Select(m => m.Name));
addStr.Append($@"insert into {typeName} ({noIdNameStr}) values ({string.Join(",", type.GetProperties().Where(m => !m.Name.Equals("Id")).Select(m =>$"@{m.Name}"))})");
getStr.Append($@"select {nameStr} from {typeName}");
removeStr.Append($@"delete from {typeName}");
modify.Append($@"update {typeName} set");
foreach (var item in type.GetProperties().Where(m => !m.Name.Equals("Id")).Select(m => m.Name))
{
modify.Append($@" {item}=@{item},");
}
string qian = modify.ToString();
qian = qian.Remove(qian.LastIndexOf(','));
modifyStr.Append(qian);
} public bool Add(T t)
{
SqlParameter[] parameters = type.GetProperties().Where(m => !m.Name.Equals("Id")).Select(m => new SqlParameter($"@{m.Name}", m.GetValue(t) ?? DBNull.Value)).ToArray();
sql = addStr.ToString();
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
SqlCommand com = new SqlCommand(sql,conn);
com.Parameters.AddRange(parameters);
return com.ExecuteNonQuery() > 0;
}
} public bool Edit(T t)
{
SqlParameter[] parameters = type.GetProperties().Select(m => new SqlParameter($"@{m.Name}", m.GetValue(t)??DBNull.Value)).ToArray();
string edit=$" where Id = @{type.GetProperty("Id").Name}";
sql = modifyStr.ToString()+ edit;
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
com.Parameters.AddRange(parameters);
return com.ExecuteNonQuery() > 0;
}
}
private T GetT(SqlDataReader sdr)
{
T obj = Activator.CreateInstance(type) as T;
foreach (var item in type.GetProperties())
{
if (sdr[item.Name].GetType() != typeof(DBNull))
{
item.SetValue(obj, sdr[item.Name]);
}
else
{
item.SetValue(obj, null); }
}
return obj;
}
public List<T> GetAll()
{
sql = getStr.ToString();
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
SqlDataReader reader =com.ExecuteReader();
List<T> list = new List<T>();
while (reader.Read())
{
list.Add(GetT(reader));
}
return list;
}
} public bool Remove(int id)
{
string del=$" where Id = {id}";
sql = removeStr.ToString()+del;
using (SqlConnection conn = new SqlConnection(conStr))
{
conn.Open();
SqlCommand com = new SqlCommand(sql, conn);
return com.ExecuteNonQuery() > 0;
}
}
}
}

五、结束语:所有的成功都离不开努力,不要用不公平掩饰你不努力的样子

所有的成功都离不开努力,不要用不公平掩饰你不努力的样子

C#高级特性(反射)的更多相关文章

  1. Java高级特性——反射机制(第二篇)

    在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...

  2. PHP高级特性-反射Reflection以及Factory工厂设计模式的结合使用[代码实例]

    PHP高级特性-反射以及工厂设计模式的结合使用 [结合 Laravel-Admin 代码实例讲解] 利用反射来实现工厂模式的生产而无需创建特定的工厂类 本文地址http://janrs.com/?p= ...

  3. Java高级特性——反射机制(第一篇)

    ——何为动态语言,何为静态语言?(学习反射知识前,需要了解动态语言和静态语言) 动态语言 >是一类在运行时可以改变其结构的语言,例如新的函数.对象.甚至是代码可以被引进,已有的函数可以被删除或者 ...

  4. Java高级特性—反射和动态代理

    1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...

  5. JAVA高级特性反射和注解

    反射: 枚举反射泛型注解.html34.3 KB 反射, 主要是指通过类加载, 动态的访问, 检测和修改类本身状态或行为的一种能力, 并能根据自身行为的状态和结果, 调整或修改应用所描述行为的状态和相 ...

  6. Java高级特性——反射机制(完结)——反射与注解

    按照我们的学习进度,在前边我们讲过什么是注解以及注解如何定义,如果忘了,可以先回顾一下https://www.cnblogs.com/hgqin/p/13462051.html. 在学习反射和注解前, ...

  7. Java高级特性——反射机制(第三篇)

    获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...

  8. Java高级特性——反射

    感谢原文作者:peter_RD_nj 原文链接:https://www.jianshu.com/p/9be58ee20dee 注意:同一个类在JVM中只存在一份字节码对象 概述 定义 JAVA反射机制 ...

  9. 云端卫士实战录 | Java高级特性之多线程

    <实战录>导语 一转眼作为一名Java开发者已经四年多时间了,说长不长说短不短,对于java的感情还是比较深的,主要嘛毕竟它给了我饭吃.哈哈,开个玩笑.今天我想借此机会来和大家聊聊Java ...

  10. Spring框架学习[IoC容器高级特性]

    1.通过前面4篇文章对Spring IoC容器的源码分析,我们已经基本上了解了Spring IoC容器对Bean定义资源的定位.读入和解析过程,同时也清楚了当用户通过getBean方法向IoC容器获取 ...

随机推荐

  1. Josephus问题(Ⅰ)

    题目描述 n个人排成一圈,按顺时针方向依次编号1,2,3-n.从编号为1的人开始顺时针"一二"报数,报到2的人退出圈子.这样不断循环下去,圈子里的人将不断减少.最终一定会剩下一个人 ...

  2. 基于cornerstone.js的dicom医学影像查看浏览功能

    最近由于项目需求,需要医学影像.dcm文件的预览功能,功能完成后,基于原生Demo做一个开源分享. 心急的小伙伴可以先看如下基于原生js的全部代码: 一.全部代码 <!DOCTYPE html& ...

  3. C#常见的集合

    3中数组式的 Array 在内存上是连续分配的,而且元素类型是一样的 特点:读取快,可以坐标访问,增删慢.长度不变. ArrayList 不定长,连续分配的,元素没有类型限制,任何元素都当成Objec ...

  4. 「APIO2010」巡逻 题解

    来源 LCA 个人评价:lca求路径,让我发现了自己不会算树的直径(但是本人似乎没有用lca求) 1 题面 「APIO2010」巡逻 大意:有一个有n个节点的树,每条边权为1,一每天要从1号点开始,遍 ...

  5. Java核心知识体系3:异常机制详解

    1 什么是异常 异常是指程序在运行过程中发生的,由于外部问题导致的运行异常事件,如:文件找不到.网络连接失败.空指针.非法参数等. 异常是一个事件,它发生在程序运行期间,且中断程序的运行. Java ...

  6. 学习javascript知识

    开始学习了 努力----努力----努力 从今天开始 绝不 三天打鱼两天晒网 先把基础再巩固一下

  7. DolphinScheduler 功能开发:⼯作流级别任务空跑(后端),测试工作流是否正确执行...

    点击上方 蓝字关注我们 ✎ 编 者 按 在今年由中国科学院软件研究所主办的开源软件所供应链点亮计划-开源之夏活动中,有不少小伙伴提交了关于 DolphinScheduler 的项目,本期是来自成都信息 ...

  8. [网鼎杯2018]Unfinish-1|SQL注入|二次注入

    1.进入题目之后只有一个登录界面,检查源代码信息并没有发现有用的信息,尝试万能密码登录也不行,结果如下: 2.进行目录扫描,发现了注册界面:register.php,结果如下: 3.那就访问注册界面, ...

  9. 使用Python批量爬取美女图片

    运行截图 实列代码: from bs4 import BeautifulSoup import requests,re,os headers = { 'User-Agent': 'Mozilla/5. ...

  10. 公网可用的RTMP、RTSP测试地址(2021年3月)

    好多博客提到的公网可测试的RTSP和RTMP URL大多都不用了,以下是大牛直播SDK(Github)于2021年3月亲测可用的几个URL,有其他可用的URL,也欢迎大家在评论区回复. RTMP流地址 ...