C#创建安全的栈(Stack)存储结构
在C#中,用于存储的结构较多,如:DataTable,DataSet,List,Dictionary,Stack等结构,各种结构采用的存储的方式存在差异,效率也必然各有优缺点。现在介绍一种后进先出的数据结构。
谈到存储结构,我们在项目中使用的较多。对于Task存储结构,栈与队列是类似的结构,在使用的时候采用不同的方法。C#中栈(Stack)是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小。
在C#中,栈通常保存着我们代码执行的步骤。C#中的引用类型存储在栈中,在程序运行的时候,每个线程(Thread)都会维护一个自己的专属线程堆栈。当一个方法被调用的时候,主线程开始在所属程序集的元数据中,查找被调用方法,然后通过JIT即时编译并把结果(一般是本地CPU指令)放在栈顶。CPU通过总线从栈顶取指令,驱动程序以执行下去。
以上对栈这个数据结构进行了一个简单的介绍,现在看一下C#实现栈结构的底层方法:
/// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 类的新实例,该实例为空并且具有默认初始容量。 /// </summary> [__DynamicallyInvokable] public Stack(); /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 类的新实例,该实例为空,具有指定的初始容量或默认的初始容量(其中较大的一个)。 /// </summary> /// <param name="capacity"><see cref="T:System.Collections.Generic.Stack`1"/> 可包含的初始元素数。</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than zero.</exception> [__DynamicallyInvokable] public Stack(int capacity); /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 类的新实例,该实例包含从指定集合复制的元素并且具有足够的容量来容纳所复制的元素。 /// </summary> /// <param name="collection">从中复制元素的集合。</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception> [__DynamicallyInvokable] public Stack(IEnumerable<T> collection);
以上是对stack的部分方法的介绍,由于在操作数据存储的同时,会考虑到线程的安全性。
进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。线程分为前台线程和后台线程,通过Thread类新建线程默认为前台线程。当所有前台线程关闭时,所有的后台线程也会被直接终止,不会抛出异常。
接下来看一下ReaderWriterLockSlim类:
/// <summary> /// 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。 /// </summary> [__DynamicallyInvokable] [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)] public class ReaderWriterLockSlim : IDisposable { /// <summary> /// 使用默认属性值初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的新实例。 /// </summary> [__DynamicallyInvokable] public ReaderWriterLockSlim(); /// <summary> /// 在指定锁定递归策略的情况下初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的新实例。 /// </summary> /// <param name="recursionPolicy">枚举值之一,用于指定锁定递归策略。</param> [__DynamicallyInvokable] public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy); /// <summary> /// 尝试进入读取模式锁定状态。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入读取的模式。- 或 -当它已经包含写入锁时,当前线程可能不会获取读的锁定。- 或 -递归数将超出该计数器的容量。此限制是很大的应用程序应永远不会遇到它。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public void EnterReadLock(); /// <summary> /// 尝试进入读取模式锁定状态,可以选择超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入读取模式,则为 true;否则为 false。 /// </returns> /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯一允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterReadLock(TimeSpan timeout); /// <summary> /// 尝试进入读取模式锁定状态,可以选择整数超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入读取模式,则为 true;否则为 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯一允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterReadLock(int millisecondsTimeout); /// <summary> /// 尝试进入写入模式锁定状态。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已在任何模式下进入该锁。- 或 -当前线程已进入读取的模式,因此尝试进入锁定状态写模式,则会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public void EnterWriteLock(); /// <summary> /// 尝试进入写入模式锁定状态,可以选择超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入写入模式,则为 true;否则为 false。 /// </returns> /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯一允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterWriteLock(TimeSpan timeout); /// <summary> /// 尝试进入写入模式锁定状态,可以选择超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入写入模式,则为 true;否则为 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯一允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterWriteLock(int millisecondsTimeout); /// <summary> /// 尝试进入可升级模式锁定状态。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已在任何模式下进入该锁。- 或 -当前线程已进入读取的模式,因此尝试进入可升级模式将有死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public void EnterUpgradeableReadLock(); /// <summary> /// 尝试进入可升级模式锁定状态,可以选择超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入可升级模式,则为 true;否则为 false。 /// </returns> /// <param name="timeout">等待的间隔;或为 -1 毫秒,表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 为负数,但它不等于-1 毫秒为单位),这是唯一允许的值为负。- 或 -值 <paramref name="timeout"/> 大于 <see cref="F:System.Int32.MaxValue"/> 毫秒为单位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterUpgradeableReadLock(TimeSpan timeout); /// <summary> /// 尝试进入可升级模式锁定状态,可以选择超时时间。 /// </summary> /// /// <returns> /// 如果调用线程已进入可升级模式,则为 true;否则为 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒数,或为 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 属性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和当前的线程已进入该锁。- 或 -当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。- 或 -递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 为负数,但它不是等于 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),这是唯一允许的值为负。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象已被释放。</exception> [__DynamicallyInvokable] public bool TryEnterUpgradeableReadLock(int millisecondsTimeout); /// <summary> /// 减少读取模式的递归计数,并在生成的计数为 0(零)时退出读取模式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">在读取模式中,当前线程不已进入该锁。</exception> [__DynamicallyInvokable] public void ExitReadLock(); /// <summary> /// 减少写入模式的递归计数,并在生成的计数为 0(零)时退出写入模式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">当前线程不已进入写入模式的锁定。</exception> [__DynamicallyInvokable] public void ExitWriteLock(); /// <summary> /// 减少可升级模式的递归计数,并在生成的计数为 0(零)时退出可升级模式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">当前线程不已进入可升级模式的锁定。</exception> [__DynamicallyInvokable] public void ExitUpgradeableReadLock(); /// <summary> /// 释放 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 类的当前实例所使用的所有资源。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException"><see cref="P:System.Threading.ReaderWriterLockSlim.WaitingReadCount"/> 是大于零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingUpgradeCount"/> 是大于零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingWriteCount"/> 是大于零。</exception><filterpriority>2</filterpriority> [__DynamicallyInvokable] public void Dispose(); /// <summary> /// 获取一个值,该值指示当前线程是否已进入读取模式的锁定状态。 /// </summary> /// /// <returns> /// 如果当前线程已进入读取模式,则为 true;否则为 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsReadLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 获取一个值,该值指示当前线程是否已进入可升级模式的锁定状态。 /// </summary> /// /// <returns> /// 如果当前线程已进入可升级模式,则为 true;否则为 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsUpgradeableReadLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 获取一个值,该值指示当前线程是否已进入写入模式的锁定状态。 /// </summary> /// /// <returns> /// 如果当前线程已进入写入模式,则为 true;否则为 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsWriteLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 获取一个值,该值指示当前 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 对象的递归策略。 /// </summary> /// /// <returns> /// 枚举值之一,用于指定锁定递归策略。 /// </returns> [__DynamicallyInvokable] public LockRecursionPolicy RecursionPolicy { [__DynamicallyInvokable] get; } /// <summary> /// 获取已进入读取模式锁定状态的独有线程的总数。 /// </summary> /// /// <returns> /// 已进入读取模式锁定状态的独有线程的数量。 /// </returns> [__DynamicallyInvokable] public int CurrentReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取当前线程进入读取模式锁定状态的次数,用于指示递归。 /// </summary> /// /// <returns> /// 如果当前线程未进入读取模式,则为 0(零);如果线程已进入读取模式但却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入锁定模式 n - 1 次,则为 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取当前线程进入可升级模式锁定状态的次数,用于指示递归。 /// </summary> /// /// <returns> /// 如果当前线程没有进入可升级模式,则为 0;如果线程已进入可升级模式却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入可升级模式 n - 1 次,则为 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveUpgradeCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取当前线程进入写入模式锁定状态的次数,用于指示递归。 /// </summary> /// /// <returns> /// 如果当前线程没有进入写入模式,则为 0;如果线程已进入写入模式却不是以递归方式进入的,则为 1;或者如果线程已经以递归方式进入写入模式 n - 1 次,则为 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveWriteCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取等待进入读取模式锁定状态的线程总数。 /// </summary> /// /// <returns> /// 等待进入读取模式的线程总数。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取等待进入可升级模式锁定状态的线程总数。 /// </summary> /// /// <returns> /// 等待进入可升级模式的线程总数。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingUpgradeCount { [__DynamicallyInvokable] get; } /// <summary> /// 获取等待进入写入模式锁定状态的线程总数。 /// </summary> /// /// <returns> /// 等待进入写入模式的线程总数。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingWriteCount { [__DynamicallyInvokable] get; } }
以上是对Stack和线程的相关知识的浅述,现在介绍一下线程安全的Stack:
/// <summary> /// 表示对象的后进先出线程安全集合(栈结构) /// </summary> /// <typeparam name="T"></typeparam> public class TStack<T> : IEnumerable<T>, ICollection { /// <summary> /// 内部堆栈 /// </summary> private readonly Stack<T> _mStack; /// <summary> /// 锁访问堆栈(用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。) /// </summary> private readonly ReaderWriterLockSlim _lockStack = new ReaderWriterLockSlim(); /// <summary> /// 仅用于SyncRoot属性 /// </summary> private readonly object _objSyncRoot = new object(); // Variables /// <summary> /// 初始化一个新的实例 <see cref="TStack{T}"/> class. /// </summary> public TStack() { _mStack = new Stack<T>(); } /// <summary> /// 初始化一个新的实例 <see cref="TStack{T}"/> class. /// </summary> /// <param name="col"> /// 开始集合 /// </param> public TStack(IEnumerable<T> col) { _mStack = new Stack<T>(col); } // Init /// <summary> /// 获取枚举器 /// </summary> public IEnumerator<T> GetEnumerator() { Stack<T> localStack = null; // 初始化枚举器 _lockStack.PerformUsingReadLock(() => { // 创建一个m_tlist副本 localStack = new Stack<T>(_mStack); }); // 获取枚举器 foreach (T item in localStack) yield return item; } /// <summary> /// 获取枚举器 /// </summary> IEnumerator IEnumerable.GetEnumerator() { Stack<T> localStack = null; // 初始化枚举器 _lockStack.PerformUsingReadLock(() => { // 创建一个m_TList的副本 localStack = new Stack<T>(_mStack); }); // 获取枚举器 foreach (T item in localStack) yield return item; } /// <summary> /// 复制到一个数组 /// </summary> /// <param name="array"></param> /// <param name="index"></param> public void CopyTo(Array array, int index) { _lockStack.PerformUsingReadLock(() => _mStack.ToArray().CopyTo(array, index)); } /// <summary> ///堆栈中的项目数 /// </summary> public int Count { get { return _lockStack.PerformUsingReadLock(() => _mStack.Count); } } /// <summary> /// 总为真 /// </summary> public bool IsSynchronized { get { return true; } } /// <summary> ///同步根 /// </summary> public object SyncRoot { get { return _objSyncRoot; } } /// <summary> ///清除集合 /// </summary> public void Clear() { _lockStack.PerformUsingWriteLock(() => _mStack.Clear()); } // Clear /// <summary> ///如果项目在堆栈中,则为true /// </summary> /// <param name="item"></param> /// <returns></returns> public bool Contains(T item) { return _lockStack.PerformUsingReadLock(() => _mStack.Contains(item)); } // 包含 /// <summary> /// 返回堆栈中的顶部项,而不从堆栈中删除它 /// </summary> /// <returns></returns> public T Peek() { return _lockStack.PerformUsingReadLock(() => _mStack.Peek()); } // Peek /// <summary> ///删除并返回堆栈中的顶部项目 /// </summary> /// <returns></returns> public T Pop() { return _lockStack.PerformUsingWriteLock(() => _mStack.Pop()); } // Pop /// <summary> /// 将一个项目插入堆栈 /// </summary> /// <param name="item"></param> public void Push(T item) { _lockStack.PerformUsingWriteLock(() => _mStack.Push(item)); } // Push /// <summary> ///将堆栈转换为数组 /// </summary> /// <returns></returns> public T[] ToArray() { return _lockStack.PerformUsingReadLock(() => _mStack.ToArray()); } // ToArray /// <summary> /// 将容量设置为堆栈中实际的元素数量 /// </summary> public void TrimExcess() { _lockStack.PerformUsingWriteLock(() => _mStack.TrimExcess()); } }
以上的操作方法继承了IEnumerable<T>, ICollection两个接口。有兴趣的,可以对IEnumerable<T>, ICollection两个接口进行细致的了解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
相关文章
- 我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
- 这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
- 这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
- 这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
- 这篇文章主要介绍了C#中list用法,结合实例形式分析了C#中list排序、运算、转换等常见操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25