随笔 - 547  文章 - 213 评论 - 417 阅读 - 107万

 1.全部代码

全部代码

2.以下是该类的类图:



3. 下面对该类的各个成员的分析如下:

--------------------------------------------------------------------------------

1. Context属性

        private SettingsContext _Context;

        
public virtual SettingsContext Context
        {
            
get
            {
                
return this._Context;
            }
        }

 

我们看看SettingsContext类型到底是一个什么样的东西:

    [Serializable]

    
public class SettingsContext : Hashtable
    {

    }
 

 

原来就是一个Hashtable,那么Context的作用可能就是存储当前页面上下文的一个HashTable,但在该类中还没有任何内容,是个虚方法。以后研究到实现它的类的时候,再补充这部分内容

2. IsSynchronized属性

       private bool _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属性那?

请看下面的代码

       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;
        }

从这个函数可以看出,在查找某个属性的值的时候,先在Properties属性中进行寻找,如果找不到,就抛出异常。如果找到了,再到 PropertyValues属性中取出对应的值,这样的设计就类似于一种数据库设计:在一个表中存储一个或者几个简单的字段,在另一个表中存储较多的字段,这样在查询的时候可以先查询较少字段的表,然后再查较多字段的表,这样就避免将大数据量的表加入内存

不知道我这里对于这两个类的分析是否正确?

5. Providers属性:

       private SettingsProviderCollection _Providers;

        
public virtual SettingsProviderCollection Providers
        {
            
get
            {
                
return this._Providers;
            }
        }

存储该类对应的Provider.

SettingProviderCollection类已经在另外一篇文章中进行说明

6. this[string propertyName]方法:

 

        public virtual object 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方法:

        private void GetPropertiesFromProvider(SettingsProvider provider)
        {
            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的所有属性集合。下面我们深入研究一下这一句:

SettingsPropertyValueCollection collection2 = provider.GetPropertyValues(this.Context, collection1);

 

看一下调用这一句的时候到底执行了什么操作:

   public abstract class SettingsProvider : ProviderBase
    {
        
protected SettingsProvider()
        {
        }

        
public abstract SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection);

        
public abstract void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection);

 
        
public abstract string ApplicationName { getset; }

    }

可以看到,SettingProvider中的GetPropertyValues只是一个虚方法,看到要到实现他的具体的类中去寻找。

 

    public abstract class ProfileProvider : SettingsProvider
    {
        
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,但是里面的方法仍然是虚方法。我们继续向下找:

    public class SqlProfileProvider : ProfileProvider

SqlProfileProvider继承了ProfileProvider,这里面的方法就不是虚方法了。我们具体看看里面的GetPropertyValues方法:

       public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext sc, SettingsPropertyCollection properties)
        {
            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,这个比较容易理解,就是一个属性值只能从一个数据表或者数据操作中获得

3GetPropertiesFromProvider方法是根据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对应的属性集合的更改写入数据库

13Save方法

        public virtual void Save()
        {
            
if (this.IsSynchronized)
            {
                lock (this)
                {
                    this.SaveCore();
                    
return;
                }
            }
            this.SaveCore();
        }

调用SaveCore方法,将该类实例中所有项目的更改写入到数据库中。

这里要注意的是下面的这一段:

            if (this.IsSynchronized)
            {
                lock (this)
                {
                    this.SaveCore();
                    
return;
                }
            }

 

如果该类实例被设置成同步的,就要先锁定该类实例,然后再调用SaveCore方法。

 

Lock方法的研究

 

下面需要研究一下这个lock方法。以下是msdn的描述:

 

 

lock 语句(C# 参考) 

lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。此语句的形式如下:

Object thisLock = new Object();

lock (thisLock)
{
    
// Critical code section
}

有关更多信息,请参见线程同步(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# 中使用线程的简单示例。

// statements_lock.cs
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();
    }
}

输出

RunMe called

 

下例使用线程和 lock。只要 lock 语句存在,语句块就是临界区并且 balance 永远不会是负数。

// statements_lock2.cs
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(
1100));
        }
    }
}

 
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.   对于下面的程序:

        Account acc = new Account(1000);

        
for (int i = 0; i < 100; i++)
        {
           Withdraw(r.Next(
1100));
        }

虽然是用1000减去随机产生的数,但是经过相减后减出的最小数都是0,而不会是负数。不知道是利用了什么原理。

研究完了lock方法,我们对调用SaveCore()前面的那个lock语句的作用就了解的很明白了。是为了防止在一个线程正在更新的时候也执行更新,这样就保证了一个数据表在同一时间只有一个线程在访问。很好的解决了数据库修改并发的问题。

 

 

 

posted on   今夜太冷  阅读(708)  评论(3编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示