0、获取输入参数的实际名称
使用nameof
public static IEnumerable<T> Shrink<T>(this IEnumerable<T> list, double prop, bool both_end)
{
if (list == null)
throw new ArgumentNullException(paramName: nameof(list));
if (prop < 0)
throw new ArgumentOutOfRangeException(paramName: nameof(prop));
}
1、枚举的转换
public enum GnssMessageType { Unknown = -1, GPGGA = 218, GPRMC = 225 }
string typeName = "GPGGA";
GnssMessageType type;
//尝试转换为枚举,假如转换失败,标记为未知类型
Enum.TryParse<GnssMessageType>(typeName, out type);
if (!Enum.IsDefined(typeof(GnssMessageType), type))
type = GnssMessageType.Unknown;
2、C#判断对象类型
Student student_jack = new Student("Jack");
bool is_jack_student = student_jack is Student;
3、用反射动态绑定控件事件
容器窗体内包括一个1列2行的TableLayoutPanel控件,第1行为若干按钮,第2行等待填充其它控件;重载构造器并添加绑定事件方法
容器窗体
/// <summary>
/// 容器窗体初始化,指定要填充的子控件以及停靠方式
/// </summary>
/// <param name="child">待填充进来的子控件</param>
/// <param name="dockStyle">停靠方式,为空则按默认方式停靠</param>
public FormContainer(Control child, DockStyle? dockStyle)
{
InitializeComponent();
if (child == null)
return;
//假如为Windows窗体,则取消顶级窗口属性
if (child is Form)
((Form)child).TopLevel = false;
this.tableLayoutPanel_Main.Controls.Add(child, 0, 1); //在TableLayoutControl第1列第2行添加
this.Name = child.Name; //改变容器类名称
this.AddClickEvents(this, child); //绑定点击方法
if (dockStyle != null)
child.Dock = dockStyle.Value;
}
/// <summary>
/// 将指定控件的子控件Click委托绑定其它控件中的Click方法,假如有子控件则在子控件中查找
/// </summary>
/// <param name="body">在其下子控件中寻找Click委托的控件</param>
/// <param name="child">在其中寻找绑定方法的控件</param>
private void AddClickEvents(Control body, Control child)
{
//循环子控件,,否则
foreach (Control control in body.Controls)
{
//假如子控件亦有子控件则递归
if (control.HasChildren)
{
this.AddClickEvents(control, child);
continue;
}
//假如为按钮且可见则绑定Click方法,方法名称为[按钮名称_Click],区分大小写
else if (control is Button/* && control.Visible*/)
{
EventInfo click = control.GetType().GetEvent("Click"); //按名称寻找事件
MethodInfo method = child.GetType().GetMethod(string.Format("{0}_Click", control.Name), new Type[] { typeof(object), typeof(EventArgs) }); //按名称与参数寻找方法
if (method == null)
continue;
Delegate handler = Delegate.CreateDelegate(click.EventHandlerType, child, method); //TODO 第二个参数需为方法所在的控件
click.AddEventHandler(control, handler);
}
}
}
新建用户控件并添加名称符合规则的Click方法
用户控件
/// <summary>
/// 新增方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Button_Add_Click(object sender, EventArgs e)
{
object obj = this;
this.label1.Text = "444";
this.label3.Text = "666";
}
调用方法
FormContainer container = new FormContainer(new UserControlExample(), DockStyle.Fill);
this.ShowForm(container);
结果
调用结果
4、使用LAMBDA表达式(LINQ)时同时给出索引
string[] names = new string[] { "Jack", "Jameson", "Laura" };
List<string> list =
names.Select((name, index) => new { name, index })
.Where(a => a.name.StartsWith("L") || a.index == 0).ToList();
5、C#粘贴板
1)复制到粘贴板
Clipboard.SetDataObject(this.textBox_Info.Text);
Clipboard.SetText(this.textBox_Info.Text);
this.label_Copied.Visible = true;
new Thread(new ThreadStart(() =>
{
Thread.Sleep(1500);
this.label_Copied.SafeInvoke(() =>
{
this.label_Copied.Visible = false;
});
}))
{ IsBackground = true }.Start();
2)从粘贴板粘贴
// Declares an IDataObject to hold the data returned from the clipboard.
// Retrieves the data from the clipboard.
IDataObject iData = Clipboard.GetDataObject();
// Determines whether the data is in a format you can use.
if(iData.GetDataPresent(DataFormats.Text))
{
// Yes it is, so display it in a text box.
textBox2.Text = (String)iData.GetData(DataFormats.Text);
}
6、protobuf-net的应用问题
0) NUGET安装
VS内进入程序包管理器控制台输入
PM> Install-Package protobuf-net
卸载则输入以下命令
PM> Uninstall-Package protobuf-net
1) ProtoMember序号问题
不大于536870911,且应避开范围19000-19999
Notes for Identifiers
they must be positive integers (for best portability, they should be <= 536870911 and not in the range 19000-19999)
2) 构造器
假如在反序列化过程中存在有参构造器,则无参构造器亦必须同时存在
[ProtoContract]
public class SomeObject
{
[ProtoMember(1)]
public int Index { get; set; }
[ProtoMember(2)]
public DateTime Time { get; set; }
/// <summary>
/// 无参构造器,在反序列化过程中假如存在有参构造器,则亦必须同时存在
/// </summary>
public SomeObject() { }
public SomeObject(int index, DateTime time)
{
this.Index = index;
this.Time = time;
}
}
3) 字段支持
假如引用类型字段要序列化,则该类型在定义时必须支持序列化,否则不需要
[ProtoContract]
public class OtherObject
{
[ProtoMember(1)]
public string Message { get; set; }
}
[ProtoContract]
public class SomeType
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public List<int> Values { get; set; }
/// <summary>
/// Object属性,假如引用类型字段要序列化,则该类型在定义时必须支持序列化,否则不需要
/// </summary>
[ProtoMember(4)]
public SomeObject Object { get; set; }
/// <summary>
/// OtherObject属性,假如引用类型字段要序列化,则该类型在定义时必须支持序列化,否则不需要
/// </summary>
[ProtoMember(5)]
public OtherObject OtherObject { get; set; }
public override string ToString()
{
return string.Format("{0}: {1}", this.Id, this.Name);
}
}
4) 继承
继承关系必须显性地声明,且在同一个类的范围内ProtoInclude与ProtoMember的序号不可重复
[ProtoContract]
[ProtoInclude(1, typeof(SomeDerivedType))]
public class SomeBaseType
{
[ProtoMember(2)]
public int Id { get; set; }
}
[ProtoContract]
public class SomeDerivedType : SomeBaseType
{
[ProtoMember(1)]
public string Name { get; set; }
}
7、泛型中类型参数的初始化
1) default(T)
public class RadioWrapper<T>
{
private readonly T _base;
public RadioWrapper()
{
this._base = default(T);
}
}
2) 对T添加约束
public class RadioWrapper<T> where T : new()
{
private readonly T _base = default(T);
public RadioWrapper()
{
this._base = new T();
}
}
假如要对多个参数类型进行约束:
public DataSet MultiQuery<Conn, Adapter>(string connStr, IEnumerable<string> sqlStrings)
where Conn : DbConnection, IDisposable
where Adapter : DbConnection, IDisposable
{
....
}
3) 调用CreateInstance()方法
public class RadioWrapper<T> where T
{
private readonly T _base = default(T);
private readonly Type _type;
public RadioWrapper()
{
this._type = typeof(T);
this._base = (T)Activator.CreateInstance(this._type);
//this._base = (T)Assembly.GetAssembly(this._type).CreateInstance(this._type.ToString());
}
}
8、初始化泛型类
public class Machines
{
public Dictionary<string, object> DictMachine { get; set; }
public Machines()
{
this.DictMachine = new Dictionary<string, object>();
List<string> names = new List<string>() { "S1", "R1" };
Type classType = Type.GetType("ConnectServerWrapper.RadioWrapper`1"); //获取泛型类类型,命名空间+类名
foreach (var name in names)
{
Type T = Type.GetType(string.Format("gprotocol.Radio_{0}, connect_server", name)); //获取类型参数的类型,引用的类库需指明程序集名称
Type genericType = classType.MakeGenericType(T); //替代由当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的 System.Type 对象
this.DictMachine.Add(name, Activator.CreateInstance(genericType));
}
}
}
9、泛型类获取、设置属性值,调用方法
1) 获取属性值
Type type = typeof(T);
T t = (T)Activator.CreateInstance(type);
PropertyInfo property = type.GetProperty("FloatList");
List<float> float_list = (List<float>)property.GetValue(t);
float_list.Clear();
float_list.AddRange(new float[] { 0, 0, 0 });
2) 设置属性值
Type type = typeof(T);
T t = (T)Activator.CreateInstance(type);
PropertyInfo property = type.GetProperty("FloatList");
property.SetValue(t, new List<float>() { 0, 0, 0 });
3) 获取方法并调用
public static bool IsConnOpen<T>(string connStr) where T : DbConnection, IDisposable
{
Type type = typeof(T);
T connection = (T)Activator.CreateInstance(type, connStr);
MethodInfo openMethod = type.GetMethod("Open");
PropertyInfo stateProp = type.GetProperty("State");
ConnectionState state = ConnectionState.Closed;
openMethod.Invoke(connection, null);
state = (ConnectionState)stateProp.GetValue(connection);
}
10、反射调用静态泛型方法
//通过反射调用Enumerable.ElementAt方法获取List<int>的元素
List<int> list = new List<int>() { 0, 0, 0 };
//获取List<int>或其它类型集合所有的泛型的类型参数
Type[] genericTypes = list.GetType().GenericTypeArguments;
object result;
//仅在有一个类型参数的情况下继续
if (genericTypes != null && genericTypes.Length == 1)
{
//获取方法所在的类型
Type enumerableType = typeof(Enumerable);
//获取方法,并通过获取到的类型参数转化为泛型方法
MethodInfo method = enumerableType.GetMethod("ElementAt");
MethodInfo methodGeneric = method.MakeGenericMethod(genericTypes[0]);
//执行泛型方法,假如为静态方法,则第一个参数为null,第二个参数为方法所需参数的数组
result = methodGeneric.Invoke(null, new object[] { list, 0 });
}
11、CommonLib.DataUtil.OracleProvider调用存储过程返回结果集
包头:
create or replace package pag_example is
type mycursor is ref cursor;
Procedure p_example (var_flowid Varchar2,
var_fremark Varchar2,
myresult out mycursor);
end pag_example;
包体:
create or replace package body pag_example is
Procedure p_example (var_flowid Varchar2,
var_fremark Varchar2,
myresult out mycursor) is
begin
open myresult for
select * from table_example
end p_example;
end pag_example;
调用过程:
OracleProvider provider = new ("localhost", "orcl", "user_name", "user_pass");
IDataParameter[] parameters = new IDataParameter[3]
{
new OracleParameter("var_flowid", OracleDbType.Varchar2, ParameterDirection.Input) { Value = "1" },
new OracleParameter("var_fremark", OracleDbType.Varchar2) { Value = "Q" },
new OracleParameter("myresult", OracleDbType.RefCursor, ParameterDirection.Output)
};
DataTable dataTable = this.provider.RunProcedureQuery("pag_get_camera.p_camera", parameters).Tables[0];
12、Json.NET控制字段名称拼写方式与格式
//序列化设置
JsonSerializerSettings setting = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy() //lowerCamelCase
//NamingStrategy = new DefaultNamingStrategy() //UpperCamelCase
//NamingStrategy = new SnakeCaseNamingStrategy() //snake_case
//NamingStrategy = new KebabCaseNamingStrategy() //kebab-case
},
Formatting = Formatting.None //无特殊格式,一行输出
//Formatting = Formatting.Indented //带缩进多行输出
};
string result = JsonConvert.SerializeObject(new JsonSource(), setting);
name | demo |
---|---|
Default | PersonName |
CamelCase | personName |
SnakeCase | person_name |
KebabCase | person-name |
13、WPF在代码中动态添加Style
deviceStatus.Style = FindResource("FontAwesome") as Style;
deviceStatus.Text = FindResource("fa-lightbulb-o").ToString();
14、WPF在其它Style的基础上创建Style
基础Style
<Style x:Key="TabItemExWithUnderLineStyle" TargetType="{x:Type TabItem}">
...
</Style>
衍生Style
<Style x:Key="ProjectMenuTabItemStyle" TargetType="TabItem" BasedOn="{StaticResource TabItemExWithUnderLineStyle}">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Width" Value="115"/>
<Setter Property="Height" Value="38"/>
<Setter Property="Margin" Value="0, 0, 0, 0"/>
<Setter Property="Foreground" Value="Black"/>
</Style>
注意,基础Style一定要在衍生Style之前声明
15、string.Format格式字符串包含"{"与"}"的处理方式
因为String.Format会识别{},来用参数代替,但是如果字符串中包含{或者},则需要用{{ 来代替字符 {,用}} 代替 }
例如
json.Append(String.Format("{\"total\":{0},\"row\":{1}}", lineCount, strJSON));
运行时会报错,
若用如下代码来代替,则可以正确运行:
json.Append(String.Format("{{\"total\":{0},\"row\":{1}}}", lineCount, strJSON));
16、类或结构实现比较器
实现IComparable<T>接口
public struct DistAlarm : IComparable<DistAlarm>
{
public double Dist { get; set; }
public int Alarm { get; set; }
public DistAlarm(double dist, int alarm)
{
Dist = dist;
Alarm = alarm;
}
public override int GetHashCode()
{
return Dist.GetHashCode() | Alarm.GetHashCode();
}
#region 是否相等的比较
public override bool Equals(object obj)
{
return obj is DistAlarm && Dist == ((DistAlarm)obj).Dist && Alarm == ((DistAlarm)obj).Alarm;
}
public static bool operator ==(DistAlarm left, DistAlarm right)
{
return left.Equals(right);
}
public static bool operator !=(DistAlarm left, DistAlarm right)
{
return !(left == right);
}
#endregion
#region 大小的比较
public int CompareTo(DistAlarm other)
{
return Dist.CompareTo(other.Dist);
}
public static bool operator <(DistAlarm left, DistAlarm right)
{
return left.CompareTo(right) < 0;
}
public static bool operator <=(DistAlarm left, DistAlarm right)
{
return left.CompareTo(right) <= 0;
}
public static bool operator >(DistAlarm left, DistAlarm right)
{
return left.CompareTo(right) > 0;
}
public static bool operator >=(DistAlarm left, DistAlarm right)
{
return left.CompareTo(right) >= 0;
}
#endregion
}
17、含中文字符串与PLC字符类型的互相转化
含中文字符串编码为sbyte类型(指取值范围)数组,然后可根据需要将这些值写入PLC字符类型标签的每一位中
string source = "首钢京唐A"; //源中文字符串
byte[] bytes = Encoding.Default.GetBytes(source); //用默认编码编码为byte数组
int[] numbers = bytes.Select(b => b > 127 ? b - 256 : b).ToArray(); //调整取值范围(AB公司PLC内字符串每一位字符取值范围为-128~127)
//numbers = { -54, -41, -72, -42, -66, -87, -52, -58, 65 }
从PLC字符类型标签中分别获取每一位的值,并解码为含中文字符串
方法1:转化为URL编码并通过GB2312解码为字符串
string step1 = string.Join(string.Empty, numbers.Select(n => n < 0 ? n + 256 : n).Select(n => '%' + n.ToString("X2")).ToArray());
//step1 = "%CA%D7%B8%D6%BE%A9%CC%C6%41";
string test = HttpUtility.UrlDecode(step1, Encoding.GetEncoding("GB2312"));
方法2:调整回byte类型取值范围并解码为字符串
byte[] step2 = numbers.Select(n => (byte)(n < 0 ? n + 256 : n)).ToArray();
test = Encoding.Default.GetString(step2);
18、使程序以获取管理员权限的方式运行
一、启用ClickOnce安全设置
在Visual Studio中,解决方案资源管理器--右键项目名称--属性,找到“安全性”选项,勾选“启用ClickOnce安全设置”
启用ClickOnce安全设置
二、修改清单文件
上一步操作后,项目下面会多出一个名为“app.manifest”的文件
app.manifest文件位置选中它,并找到元素<requestedExecutionLevel level="asInvoker" uiAccess="false" />,将其改为:<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />,
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。n
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
元素。
-->
<!--<requestedExecutionLevel level="asInvoker" uiAccess="false" />-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
三、取消勾选ClickOnce
改正后,不要急于重新编译生成,再次打开“属性--安全性”界面,将“启用ClickOnce安全设置”前面的勾去掉后再编译运行,不然程序会报错无法运行。
取消勾选ClickOnce四、重新编译运行程序
打开程序时,会提示“用户账户控制”来获取管理员权限运行,点击“是”获取管理员权限。
19、使Windows服务具有足够的权限
设置为LocalSystem账户将服务的启动账户设置为LocalSystem这个特权账户,或者具有特殊权限的用户账户,而非其它受限的账户。
网友评论