1.全部代码

2.以下是该类的类图:
略
3. 下面对该类的各个成员的分析如下:
--------------------------------------------------------------------------------
1. Context属性
public virtual SettingsContext Context
{
get
{
return this._Context;
}
}
我们看看SettingsContext类型到底是一个什么样的东西:
public class SettingsContext : Hashtable
{
}
原来就是一个Hashtable,那么Context的作用可能就是存储当前页面上下文的一个HashTable,但在该类中还没有任何内容,是个虚方法。以后研究到实现它的类的时候,再补充这部分内容
2. IsSynchronized属性
public bool IsSynchronized
{
get
{
return this._IsSynchronized;
}
}
判断该类是否被同步
3.Properties属性
private SettingsPropertyCollection _Properties;
public virtual SettingsPropertyCollection Properties
{
get
{
return this._Properties;
}
}
操作的是一个SettingPropertyCollection类型的变量
4. PropertyValues属性
private SettingsPropertyValueCollection _PropertyValues;
public virtual SettingsPropertyValueCollection PropertyValues
{
get
{
return this._PropertyValues;
}
}
操作的是一个SettingsPropertyValueCollection类型的变量
到了这里,就会想到,为什么已经有了Properties属性,为什么还要PropertyValues属性那?
请看下面的代码
{
if (((this.Properties == null) || (this._PropertyValues == null)) || (this.Properties.Count == 0))
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
SettingsProperty property1 = this.Properties[propertyName];
if (property1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
SettingsPropertyValue value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
this.GetPropertiesFromProvider(property1.Provider);
value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
}
return value1.PropertyValue;
}
从这个函数可以看出,在查找某个属性的值的时候,先在Properties属性中进行寻找,如果找不到,就抛出异常。如果找到了,再到 PropertyValues属性中取出对应的值,这样的设计就类似于一种数据库设计:在一个表中存储一个或者几个简单的字段,在另一个表中存储较多的字段,这样在查询的时候可以先查询较少字段的表,然后再查较多字段的表,这样就避免将大数据量的表加入内存
不知道我这里对于这两个类的分析是否正确?
5. Providers属性:
public virtual SettingsProviderCollection Providers
{
get
{
return this._Providers;
}
}
存储该类对应的Provider.
SettingProviderCollection类已经在另外一篇文章中进行说明
6. this[string propertyName]方法:
{
get
{
if (this.IsSynchronized)
{
lock (this)
{
return this.GetPropertyValueByName(propertyName);
}
}
return this.GetPropertyValueByName(propertyName);
}
set
{
if (this.IsSynchronized)
{
lock (this)
{
this.SetPropertyValueByName(propertyName, value);
return;
}
}
this.SetPropertyValueByName(propertyName, value);
}
}
根据属性名称返回或者设置属性的值
7. GetPropertiesFromProvider方法:
{
SettingsPropertyCollection collection1 = new SettingsPropertyCollection();
foreach (SettingsProperty property1 in this.Properties)
{
if (property1.Provider == provider)
{
collection1.Add(property1);
}
}
if (collection1.Count > 0)
{
SettingsPropertyValueCollection collection2 = provider.GetPropertyValues(this.Context, collection1);
foreach (SettingsPropertyValue value1 in collection2)
{
if (this._PropertyValues[value1.Name] == null)
{
this._PropertyValues.Add(value1);
}
}
}
}
获得使用指定Provider的所有属性集合。下面我们深入研究一下这一句:
看一下调用这一句的时候到底执行了什么操作:
{
protected SettingsProvider()
{
}
public abstract SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection);
public abstract void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection);
public abstract string ApplicationName { get; set; }
}
可以看到,SettingProvider中的GetPropertyValues只是一个虚方法,看到要到实现他的具体的类中去寻找。
{
protected ProfileProvider()
{
}
public abstract int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate);
public abstract int DeleteProfiles(string[] usernames);
public abstract int DeleteProfiles(ProfileInfoCollection profiles);
public abstract ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords);
public abstract ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords);
public abstract ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords);
public abstract ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords);
public abstract int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate);
}
ProfileProvider 继承了SettingsProvider,但是里面的方法仍然是虚方法。我们继续向下找:
SqlProfileProvider继承了ProfileProvider,这里面的方法就不是虚方法了。我们具体看看里面的GetPropertyValues方法:
{
SettingsPropertyValueCollection collection1 = new SettingsPropertyValueCollection();
if (properties.Count >= 1)
{
string text1 = (string) sc["UserName"];
foreach (SettingsProperty property1 in properties)
{
if (property1.SerializeAs == SettingsSerializeAs.ProviderSpecific)
{
if (property1.PropertyType.IsPrimitive || (property1.PropertyType == typeof(string)))
{
property1.SerializeAs = SettingsSerializeAs.String;
}
else
{
property1.SerializeAs = SettingsSerializeAs.Xml;
}
}
collection1.Add(new SettingsPropertyValue(property1));
}
if ((text1 != null) && (text1.Length > 0))
{ this.GetPropertyValuesFromDatabase(text1, collection1);
}
}
return collection1;
}
进一个看一下这个方法调用的GetPropertyValuesFromDatabase方法
private void GetPropertyValuesFromDatabase(string userName, SettingsPropertyValueCollection svc)
{
HttpContext context1 = HttpContext.Current;
string[] textArray1 = null;
string text1 = null;
byte[] buffer1 = null;
if (context1 != null)
{
if (!context1.Request.IsAuthenticated)
{
AnonymousIdUtil.GetAnonymousId(context1);
}
else
{
string text2 = context1.User.Identity.Name;
}
}
try
{
SqlConnectionHolder holder1 = null;
SqlDataReader reader1 = null;
try
{
holder1 = SqlConnectionHelper.GetConnection(this._sqlConnectionString, true);
this.CheckSchemaVersion(holder1.Connection);
SqlCommand command1 = new SqlCommand("dbo.aspnet_Profile_GetProperties", holder1.Connection);
command1.CommandTimeout = this.CommandTimeout;
command1.CommandType = CommandType.StoredProcedure;
command1.Parameters.Add(this.CreateInputParam("@ApplicationName", SqlDbType.NVarChar, this.ApplicationName));
command1.Parameters.Add(this.CreateInputParam("@UserName", SqlDbType.NVarChar, userName));
command1.Parameters.Add(this.GetTimeZoneAdjustmentParam());
reader1 = command1.ExecuteReader(CommandBehavior.SingleRow);
if (reader1.Read())
{
textArray1 = reader1.GetString(0).Split(new char[] { ':' });
text1 = reader1.GetString(1);
int num1 = (int) reader1.GetBytes(2, (long) 0, null, 0, 0);
buffer1 = new byte[num1];
reader1.GetBytes(2, (long) 0, buffer1, 0, num1);
}
}
finally
{
if (holder1 != null)
{
holder1.Close();
holder1 = null;
}
if (reader1 != null)
{
reader1.Close();
}
}
ProfileModule.ParseDataFromDB(textArray1, text1, buffer1, svc);
}
catch
{
throw;
}
}
上面的方法就是从根据当前用户名称,从数据库中取出该用户的属性集合,返回一个PropertyValueCollection的集合
在这个方法中用到了很多的其他类,比如SqlConnectionHolder类,这些类将在另外一篇文章中进行论述
8. GetPropertyValueByName方法
private object GetPropertyValueByName(string propertyName)
{
if (((this.Properties == null) || (this._PropertyValues == null)) || (this.Properties.Count == 0))
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
SettingsProperty property1 = this.Properties[propertyName];
if (property1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
SettingsPropertyValue value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
this.GetPropertiesFromProvider(property1.Provider);
value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
}
return value1.PropertyValue;
}
根据属性的名称获得属性的值。
这里面的这一句需要注意:
if (value1 == null)
{
this.GetPropertiesFromProvider(property1.Provider);
value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
}
如果当前属性的值为null,就从数据库中加载.调用的GetPropertiesFromProvider将从数据库中加载当前用户的所有属性,这样其他属性就不用再次加载。
我想这段代码应该在首次执行的时候执行,以后执行就不会出现 value1 == null 的情况了
到了这里,可以对Provider在该类中的使用作一个总结:
1. 该类中有一个属性Providers,这个属性存储的是该类代表的集合中所有项对应的Provider的集合
2. 集合中的一个项只能有一个Provider,这个比较容易理解,就是一个属性值只能从一个数据表或者数据操作中获得
3.GetPropertiesFromProvider方法是根据Provider的名称获得所有使用该Provider的项的值的集合
9. Initialize初始化函数:
public void Initialize(SettingsContext context, SettingsPropertyCollection properties, SettingsProviderCollection providers)
{
this._Context = context;
this._Properties = properties;
this._Providers = providers;
}
用指定cscontext, properties,providers初始化该类的实例
10. SetPropertyValueByName方法
private void SetPropertyValueByName(string propertyName, object propertyValue)
{
if (((this.Properties == null) || (this._PropertyValues == null)) || (this.Properties.Count == 0))
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
SettingsProperty property1 = this.Properties[propertyName];
if (property1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
if (property1.IsReadOnly)
{
throw new SettingsPropertyIsReadOnlyException("SettingsPropertyReadOnly: " + propertyName);
}
if ((propertyValue != null) && !property1.PropertyType.IsInstanceOfType(propertyValue))
{
throw new SettingsPropertyWrongType("SettingsPropertyWrongType: " + propertyName);
}
SettingsPropertyValue value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
this.GetPropertiesFromProvider(property1.Provider);
value1 = this._PropertyValues[propertyName];
if (value1 == null)
{
throw new SettingsPropertyNotFoundException("SettingsPropertyNotFound: " + propertyName);
}
}
value1.PropertyValue = propertyValue;
}
这个方法先从Properties属性中查找是否存在这个属性,如果存在就为PropertyValues属性的相关项设置值。
11. Synchronized方法
public static SettingsBase Synchronized(SettingsBase settingsBase)
{
settingsBase._IsSynchronized = true;
return settingsBase;
}
将一个SettingsBase对象的_IsSynchronized属性设置为true
12. SaveCore方法
private void SaveCore()
{
if (((this.Properties != null) && (this._PropertyValues != null)) && (this.Properties.Count != 0))
{
foreach (SettingsProvider provider1 in this.Providers)
{
SettingsPropertyValueCollection collection1 = new SettingsPropertyValueCollection();
foreach (SettingsPropertyValue value1 in this.PropertyValues)
{
if (value1.Property.Provider == provider1)
{
collection1.Add(value1);
}
}
if (collection1.Count > 0)
{
provider1.SetPropertyValues(this.Context, collection1);
}
}
foreach (SettingsPropertyValue value2 in this.PropertyValues)
{
value2.IsDirty = false;
}
}
}
操作数据库,将每一个Provider对应的属性集合的更改写入数据库
13.Save方法
{
if (this.IsSynchronized)
{
lock (this)
{
this.SaveCore();
return;
}
}
this.SaveCore();
}
调用SaveCore方法,将该类实例中所有项目的更改写入到数据库中。
这里要注意的是下面的这一段:
{
lock (this)
{
this.SaveCore();
return;
}
}
如果该类实例被设置成同步的,就要先锁定该类实例,然后再调用SaveCore方法。
Lock方法的研究
下面需要研究一下这个lock方法。以下是msdn的描述:
lock 语句(C# 参考)
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。此语句的形式如下:







有关更多信息,请参见线程同步(C# 编程指南)。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
线程处理(C# 编程指南) 这节讨论了线程处理。
lock 调用块开始位置的 Enter 和块结束位置的 Exit。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
· 如果实例可以被公共访问,将出现 lock (this) 问题。
· 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
· 由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。
最佳做法是定义 private 对象来锁定, 或 private shared 对象变量来保护所有实例所共有的数据。
下例显示的是在 C# 中使用线程的简单示例。
using System;
using System.Threading;
class ThreadTest
{
public void RunMe()
{
Console.WriteLine("RunMe called");
}
static void Main()
{
ThreadTest b = new ThreadTest();
Thread t = new Thread(b.RunMe);
t.Start();
}
}
输出
下例使用线程和 lock。只要 lock 语句存在,语句块就是临界区并且 balance 永远不会是负数。
using System;
using System.Threading;
class Account
{
private Object thisLock = new Object();
int balance;
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
int Withdraw(int amount)
{
// This condition will never be true unless the lock statement
// is commented out:
if (balance < 0)
{
throw new Exception("Negative Balance");
}
// Comment out the next line to see the effect of leaving out
// the lock keyword:
lock(thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
}
public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class Test
{
static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}
我们测试一下给出的这段程序,测试结果如下
1. 对于下面的程序:
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
虽然是用1000减去随机产生的数,但是经过相减后减出的最小数都是0,而不会是负数。不知道是利用了什么原理。
研究完了lock方法,我们对调用SaveCore()前面的那个lock语句的作用就了解的很明白了。是为了防止在一个线程正在更新的时候也执行更新,这样就保证了一个数据表在同一时间只有一个线程在访问。很好的解决了数据库修改并发的问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架