如果一种类型的对象需要经常被创建、销毁,为了提高性能,我们通常需要使用“池”技术,就如线程池、TCP连接池等一样。那么需要使用池技术的对象一般有哪些特征了?
publicinterfaceIObjectPool


{
//objType为缓存的对象的类型,cArgs为缓存对象的构造参数
boolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum);
objectRentObject();
voidGiveBackObject(intobjHashCode);
voidDispose();


intMinObjCount
{get;}

intMaxObjCount
{get;}

intCurObjCount
{get;}

intIdleObjCount
{get;}

eventCallBackObjPoolPoolShrinked;
eventCallBackObjPoolMemoryUseOut;//内存分配失败
}

publicdelegatevoidCallBackObjPool();
publicinterfaceIPooledObjSupporter:IDisposable


{
voidReset();//恢复对象为初始状态,当IObjectPool.GiveBackObject时调用
}
usingSystem;
usingSystem.Collections;
usingSystem.Reflection;

namespaceEnterpriseServerBase.Infrastructure


{

/**////<summary>
///IObjectPool的默认实现。
///作者:朱伟sky.zhuwei@163.com
///</summary>

ObjectPool#regionObjectPool
publicclassObjectPool:IObjectPool


{

members#regionmembers
privateTypedestType=null;
privateobject[]ctorArgs=null;
privateintminObjCount=0;
privateintmaxObjCount=0;
privateintshrinkPoint=0;
privateHashtablehashTableObjs=newHashtable();
privateHashtablehashTableStatus=newHashtable();//key-isIdle其中key就是hashcode
privateArrayListkeyList=newArrayList();
privateboolsupportReset=false;
#endregion


IObjectPool成员#regionIObjectPool成员
publiceventCallBackObjPoolPoolShrinked;
publiceventCallBackObjPoolMemoryUseOut;

publicboolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum)


{
if(minNum<1)


{
minNum=1;
}
if(maxNum<5)


{
maxNum=5;
}

this.destType=objType;
this.ctorArgs=cArgs;
this.minObjCount=minNum;
this.maxObjCount=maxNum;
doublecof=1-((double)minNum/(double)maxNum);
this.shrinkPoint=(int)(cof*minNum);

//缓存的类型是否支持IPooledObjSupporter接口
TypesupType=typeof(IPooledObjSupporter);
if(supType.IsAssignableFrom(objType))


{
this.supportReset=true;
}

this.InstanceObjects();

returntrue;
}

privatevoidInstanceObjects()


{
for(inti=0;i<this.minObjCount;i++)


{
this.CreateOneObject();
}
}


CreateOneObject,DistroyOneObject#regionCreateOneObject,DistroyOneObject
privateintCreateOneObject()


{
objectobj=null;

try


{
obj=Activator.CreateInstance(this.destType,this.ctorArgs);
}
catch(Exceptionee)//分配内存失败!


{
ee=ee;
this.maxObjCount=this.CurObjCount;
if(this.minObjCount>this.CurObjCount)


{
this.minObjCount=this.CurObjCount;
}

if(this.MemoryUseOut!=null)


{
this.MemoryUseOut();
}

return-1;
}

intkey=obj.GetHashCode();
this.hashTableObjs.Add(key,obj);
this.hashTableStatus.Add(key,true);
this.keyList.Add(key);

returnkey;
}

privatevoidDistroyOneObject(intkey)


{
objecttarget=this.hashTableObjs[key];
IDisposabletar=targetasIDisposable;
if(tar!=null)


{
tar.Dispose();
}

this.hashTableObjs.Remove(key);
this.hashTableStatus.Remove(key);
this.keyList.Remove(key);
}
#endregion

publicobjectRentObject()


{
lock(this)


{
objecttarget=null;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])//isIdle


{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
break;
}
}

if(target==null)


{
if(this.keyList.Count<this.maxObjCount)


{
intkey=this.CreateOneObject();
if(key!=-1)


{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
}
}
}

returntarget;
}

}


GiveBackObject#regionGiveBackObject
publicvoidGiveBackObject(intobjHashCode)


{
if(this.hashTableStatus[objHashCode]==null)


{
return;
}

lock(this)


{
this.hashTableStatus[objHashCode]=true;
if(this.supportReset)


{
IPooledObjSupportersupporter=(IPooledObjSupporter)this.hashTableObjs[objHashCode];
supporter.Reset();
}

if(this.CanShrink())


{
this.Shrink();
}
}
}

//能够收缩对象池
privateboolCanShrink()


{
intidleCount=this.GetIdleObjCount();
intbusyCount=this.CurObjCount-idleCount;

return(busyCount<this.shrinkPoint)&&(this.CurObjCount>(this.minObjCount+(this.maxObjCount-this.minObjCount)/2));
}

privatevoidShrink()


{
while(this.CurObjCount>this.minObjCount)


{
intdestKey=-1;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])


{
destKey=key;
break;
}
}

if(destKey!=-1)


{
this.DistroyOneObject(destKey);
}
else


{
break;
}
}

if(this.PoolShrinked!=null)


{
this.PoolShrinked();
}
}
#endregion

publicvoidDispose()


{
TypesupType=typeof(System.IDisposable);
if(supType.IsAssignableFrom(this.destType))


{
ArrayListlist=(ArrayList)this.keyList.Clone();
foreach(intkeyinlist)


{
this.DistroyOneObject(key);
}
}

this.hashTableStatus.Clear();
this.hashTableObjs.Clear();
this.keyList.Clear();
}


property#regionproperty
publicintMinObjCount


{
get


{
returnthis.minObjCount;
}
}

publicintMaxObjCount


{
get


{
returnthis.maxObjCount;
}
}

publicintCurObjCount


{
get


{
returnthis.keyList.Count;
}
}

publicintIdleObjCount


{
get


{
lock(this)


{
returnthis.GetIdleObjCount();
}
}
}

privateintGetIdleObjCount()


{
intcount=0;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])


{
++count;
}
}

returncount;
}
#endregion

#endregion
}
#endregion
}
publicinterfaceIPooledObjSupporter:IDisposable


{
voidReset();//恢复对象为初始状态,当IObjectPool.GiveBackObject时调用
}
usingSystem;
usingSystem.Collections;
usingSystem.Reflection;

namespaceEnterpriseServerBase.Infrastructure


{

/**////<summary>
///IObjectPool的默认实现。
///作者:朱伟sky.zhuwei@163.com
///</summary>

ObjectPool#regionObjectPool
publicclassObjectPool:IObjectPool


{

members#regionmembers
privateTypedestType=null;
privateobject[]ctorArgs=null;
privateintminObjCount=0;
privateintmaxObjCount=0;
privateintshrinkPoint=0;
privateHashtablehashTableObjs=newHashtable();
privateHashtablehashTableStatus=newHashtable();//key-isIdle其中key就是hashcode
privateArrayListkeyList=newArrayList();
privateboolsupportReset=false;
#endregion


IObjectPool成员#regionIObjectPool成员
publiceventCallBackObjPoolPoolShrinked;
publiceventCallBackObjPoolMemoryUseOut;

publicboolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum)


{
if(minNum<1)


{
minNum=1;
}
if(maxNum<5)


{
maxNum=5;
}

this.destType=objType;
this.ctorArgs=cArgs;
this.minObjCount=minNum;
this.maxObjCount=maxNum;
doublecof=1-((double)minNum/(double)maxNum);
this.shrinkPoint=(int)(cof*minNum);

//缓存的类型是否支持IPooledObjSupporter接口
TypesupType=typeof(IPooledObjSupporter);
if(supType.IsAssignableFrom(objType))


{
this.supportReset=true;
}

this.InstanceObjects();

returntrue;
}

privatevoidInstanceObjects()


{
for(inti=0;i<this.minObjCount;i++)


{
this.CreateOneObject();
}
}


CreateOneObject,DistroyOneObject#regionCreateOneObject,DistroyOneObject
privateintCreateOneObject()


{
objectobj=null;

try


{
obj=Activator.CreateInstance(this.destType,this.ctorArgs);
}
catch(Exceptionee)//分配内存失败!


{
ee=ee;
this.maxObjCount=this.CurObjCount;
if(this.minObjCount>this.CurObjCount)


{
this.minObjCount=this.CurObjCount;
}

if(this.MemoryUseOut!=null)


{
this.MemoryUseOut();
}

return-1;
}

intkey=obj.GetHashCode();
this.hashTableObjs.Add(key,obj);
this.hashTableStatus.Add(key,true);
this.keyList.Add(key);

returnkey;
}

privatevoidDistroyOneObject(intkey)


{
objecttarget=this.hashTableObjs[key];
IDisposabletar=targetasIDisposable;
if(tar!=null)


{
tar.Dispose();
}

this.hashTableObjs.Remove(key);
this.hashTableStatus.Remove(key);
this.keyList.Remove(key);
}
#endregion

publicobjectRentObject()


{
lock(this)


{
objecttarget=null;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])//isIdle


{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
break;
}
}

if(target==null)


{
if(this.keyList.Count<this.maxObjCount)


{
intkey=this.CreateOneObject();
if(key!=-1)


{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
}
}
}

returntarget;
}

}


GiveBackObject#regionGiveBackObject
publicvoidGiveBackObject(intobjHashCode)


{
if(this.hashTableStatus[objHashCode]==null)


{
return;
}

lock(this)


{
this.hashTableStatus[objHashCode]=true;
if(this.supportReset)


{
IPooledObjSupportersupporter=(IPooledObjSupporter)this.hashTableObjs[objHashCode];
supporter.Reset();
}

if(this.CanShrink())


{
this.Shrink();
}
}
}

//能够收缩对象池
privateboolCanShrink()


{
intidleCount=this.GetIdleObjCount();
intbusyCount=this.CurObjCount-idleCount;

return(busyCount<this.shrinkPoint)&&(this.CurObjCount>(this.minObjCount+(this.maxObjCount-this.minObjCount)/2));
}

privatevoidShrink()


{
while(this.CurObjCount>this.minObjCount)


{
intdestKey=-1;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])


{
destKey=key;
break;
}
}

if(destKey!=-1)


{
this.DistroyOneObject(destKey);
}
else


{
break;
}
}

if(this.PoolShrinked!=null)


{
this.PoolShrinked();
}
}
#endregion

publicvoidDispose()


{
TypesupType=typeof(System.IDisposable);
if(supType.IsAssignableFrom(this.destType))


{
ArrayListlist=(ArrayList)this.keyList.Clone();
foreach(intkeyinlist)


{
this.DistroyOneObject(key);
}
}

this.hashTableStatus.Clear();
this.hashTableObjs.Clear();
this.keyList.Clear();
}


property#regionproperty
publicintMinObjCount


{
get


{
returnthis.minObjCount;
}
}

publicintMaxObjCount


{
get


{
returnthis.maxObjCount;
}
}

publicintCurObjCount


{
get


{
returnthis.keyList.Count;
}
}

publicintIdleObjCount


{
get


{
lock(this)


{
returnthis.GetIdleObjCount();
}
}
}

privateintGetIdleObjCount()


{
intcount=0;
foreach(intkeyinthis.keyList)


{
if((bool)this.hashTableStatus[key])


{
++count;
}
}

returncount;
}
#endregion

#endregion
}
#endregion
}
(1)创建过程耗时
(2)不需要保存客户状态
(3)对象体积较大
(4)频繁创建/销毁
为了省事,我希望实现一个万能对象池组件,该对象池可以缓存任意类型的对象。下面给出对象池的接口:
publicinterfaceIObjectPool

{
//objType为缓存的对象的类型,cArgs为缓存对象的构造参数
boolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum);
objectRentObject();
voidGiveBackObject(intobjHashCode);
voidDispose();

intMinObjCount
{get;}
intMaxObjCount
{get;}
intCurObjCount
{get;}
intIdleObjCount
{get;}
eventCallBackObjPoolPoolShrinked;
eventCallBackObjPoolMemoryUseOut;//内存分配失败
}
publicdelegatevoidCallBackObjPool();
上面接口中的各个方法的含义很清楚。其中PoolShrinked表示池中的对象个数有Max变为Min。
我们可以考虑这样一种情况,当我们需要缓存的对象需要维持和一个客户之间的状态,那么也是可以的,如果是这样,所缓存的类型最好实现下面的IPooledObjSupporter接口。
publicinterfaceIPooledObjSupporter:IDisposable

{
voidReset();//恢复对象为初始状态,当IObjectPool.GiveBackObject时调用
}
对象在实现该接口后,就可以被对象池在收到归还的对象时重置其状态了。整个对象池的实现代码如下:
usingSystem;
usingSystem.Collections;
usingSystem.Reflection;
namespaceEnterpriseServerBase.Infrastructure

{
/**////<summary>
///IObjectPool的默认实现。
///作者:朱伟sky.zhuwei@163.com
///</summary>
ObjectPool#regionObjectPool
publicclassObjectPool:IObjectPool

{
members#regionmembers
privateTypedestType=null;
privateobject[]ctorArgs=null;
privateintminObjCount=0;
privateintmaxObjCount=0;
privateintshrinkPoint=0;
privateHashtablehashTableObjs=newHashtable();
privateHashtablehashTableStatus=newHashtable();//key-isIdle其中key就是hashcode
privateArrayListkeyList=newArrayList();
privateboolsupportReset=false;
#endregion

IObjectPool成员#regionIObjectPool成员
publiceventCallBackObjPoolPoolShrinked;
publiceventCallBackObjPoolMemoryUseOut;
publicboolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum)

{
if(minNum<1)

{
minNum=1;
}
if(maxNum<5)

{
maxNum=5;
}
this.destType=objType;
this.ctorArgs=cArgs;
this.minObjCount=minNum;
this.maxObjCount=maxNum;
doublecof=1-((double)minNum/(double)maxNum);
this.shrinkPoint=(int)(cof*minNum);
//缓存的类型是否支持IPooledObjSupporter接口
TypesupType=typeof(IPooledObjSupporter);
if(supType.IsAssignableFrom(objType))

{
this.supportReset=true;
}
this.InstanceObjects();
returntrue;
}
privatevoidInstanceObjects()

{
for(inti=0;i<this.minObjCount;i++)

{
this.CreateOneObject();
}
}

CreateOneObject,DistroyOneObject#regionCreateOneObject,DistroyOneObject
privateintCreateOneObject()

{
objectobj=null;
try

{
obj=Activator.CreateInstance(this.destType,this.ctorArgs);
}
catch(Exceptionee)//分配内存失败!

{
ee=ee;
this.maxObjCount=this.CurObjCount;
if(this.minObjCount>this.CurObjCount)

{
this.minObjCount=this.CurObjCount;
}
if(this.MemoryUseOut!=null)

{
this.MemoryUseOut();
}
return-1;
}
intkey=obj.GetHashCode();
this.hashTableObjs.Add(key,obj);
this.hashTableStatus.Add(key,true);
this.keyList.Add(key);
returnkey;
}
privatevoidDistroyOneObject(intkey)

{
objecttarget=this.hashTableObjs[key];
IDisposabletar=targetasIDisposable;
if(tar!=null)

{
tar.Dispose();
}
this.hashTableObjs.Remove(key);
this.hashTableStatus.Remove(key);
this.keyList.Remove(key);
}
#endregion
publicobjectRentObject()

{
lock(this)

{
objecttarget=null;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])//isIdle

{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
break;
}
}
if(target==null)

{
if(this.keyList.Count<this.maxObjCount)

{
intkey=this.CreateOneObject();
if(key!=-1)

{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
}
}
}
returntarget;
}
}

GiveBackObject#regionGiveBackObject
publicvoidGiveBackObject(intobjHashCode)

{
if(this.hashTableStatus[objHashCode]==null)

{
return;
}
lock(this)

{
this.hashTableStatus[objHashCode]=true;
if(this.supportReset)

{
IPooledObjSupportersupporter=(IPooledObjSupporter)this.hashTableObjs[objHashCode];
supporter.Reset();
}
if(this.CanShrink())

{
this.Shrink();
}
}
}
//能够收缩对象池
privateboolCanShrink()

{
intidleCount=this.GetIdleObjCount();
intbusyCount=this.CurObjCount-idleCount;
return(busyCount<this.shrinkPoint)&&(this.CurObjCount>(this.minObjCount+(this.maxObjCount-this.minObjCount)/2));
}
privatevoidShrink()

{
while(this.CurObjCount>this.minObjCount)

{
intdestKey=-1;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])

{
destKey=key;
break;
}
}
if(destKey!=-1)

{
this.DistroyOneObject(destKey);
}
else

{
break;
}
}
if(this.PoolShrinked!=null)

{
this.PoolShrinked();
}
}
#endregion
publicvoidDispose()

{
TypesupType=typeof(System.IDisposable);
if(supType.IsAssignableFrom(this.destType))

{
ArrayListlist=(ArrayList)this.keyList.Clone();
foreach(intkeyinlist)

{
this.DistroyOneObject(key);
}
}
this.hashTableStatus.Clear();
this.hashTableObjs.Clear();
this.keyList.Clear();
}

property#regionproperty
publicintMinObjCount

{
get

{
returnthis.minObjCount;
}
}
publicintMaxObjCount

{
get

{
returnthis.maxObjCount;
}
}
publicintCurObjCount

{
get

{
returnthis.keyList.Count;
}
}
publicintIdleObjCount

{
get

{
lock(this)

{
returnthis.GetIdleObjCount();
}
}
}
privateintGetIdleObjCount()

{
intcount=0;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])

{
++count;
}
}
returncount;
}
#endregion
#endregion
}
#endregion
}
publicinterfaceIPooledObjSupporter:IDisposable

{
voidReset();//恢复对象为初始状态,当IObjectPool.GiveBackObject时调用
}
对象在实现该接口后,就可以被对象池在收到归还的对象时重置其状态了。整个对象池的实现代码如下:
usingSystem;
usingSystem.Collections;
usingSystem.Reflection;
namespaceEnterpriseServerBase.Infrastructure

{
/**////<summary>
///IObjectPool的默认实现。
///作者:朱伟sky.zhuwei@163.com
///</summary>
ObjectPool#regionObjectPool
publicclassObjectPool:IObjectPool

{
members#regionmembers
privateTypedestType=null;
privateobject[]ctorArgs=null;
privateintminObjCount=0;
privateintmaxObjCount=0;
privateintshrinkPoint=0;
privateHashtablehashTableObjs=newHashtable();
privateHashtablehashTableStatus=newHashtable();//key-isIdle其中key就是hashcode
privateArrayListkeyList=newArrayList();
privateboolsupportReset=false;
#endregion

IObjectPool成员#regionIObjectPool成员
publiceventCallBackObjPoolPoolShrinked;
publiceventCallBackObjPoolMemoryUseOut;
publicboolInitialize(TypeobjType,object[]cArgs,intminNum,intmaxNum)

{
if(minNum<1)

{
minNum=1;
}
if(maxNum<5)

{
maxNum=5;
}
this.destType=objType;
this.ctorArgs=cArgs;
this.minObjCount=minNum;
this.maxObjCount=maxNum;
doublecof=1-((double)minNum/(double)maxNum);
this.shrinkPoint=(int)(cof*minNum);
//缓存的类型是否支持IPooledObjSupporter接口
TypesupType=typeof(IPooledObjSupporter);
if(supType.IsAssignableFrom(objType))

{
this.supportReset=true;
}
this.InstanceObjects();
returntrue;
}
privatevoidInstanceObjects()

{
for(inti=0;i<this.minObjCount;i++)

{
this.CreateOneObject();
}
}

CreateOneObject,DistroyOneObject#regionCreateOneObject,DistroyOneObject
privateintCreateOneObject()

{
objectobj=null;
try

{
obj=Activator.CreateInstance(this.destType,this.ctorArgs);
}
catch(Exceptionee)//分配内存失败!

{
ee=ee;
this.maxObjCount=this.CurObjCount;
if(this.minObjCount>this.CurObjCount)

{
this.minObjCount=this.CurObjCount;
}
if(this.MemoryUseOut!=null)

{
this.MemoryUseOut();
}
return-1;
}
intkey=obj.GetHashCode();
this.hashTableObjs.Add(key,obj);
this.hashTableStatus.Add(key,true);
this.keyList.Add(key);
returnkey;
}
privatevoidDistroyOneObject(intkey)

{
objecttarget=this.hashTableObjs[key];
IDisposabletar=targetasIDisposable;
if(tar!=null)

{
tar.Dispose();
}
this.hashTableObjs.Remove(key);
this.hashTableStatus.Remove(key);
this.keyList.Remove(key);
}
#endregion
publicobjectRentObject()

{
lock(this)

{
objecttarget=null;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])//isIdle

{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
break;
}
}
if(target==null)

{
if(this.keyList.Count<this.maxObjCount)

{
intkey=this.CreateOneObject();
if(key!=-1)

{
this.hashTableStatus[key]=false;
target=this.hashTableObjs[key];
}
}
}
returntarget;
}
}

GiveBackObject#regionGiveBackObject
publicvoidGiveBackObject(intobjHashCode)

{
if(this.hashTableStatus[objHashCode]==null)

{
return;
}
lock(this)

{
this.hashTableStatus[objHashCode]=true;
if(this.supportReset)

{
IPooledObjSupportersupporter=(IPooledObjSupporter)this.hashTableObjs[objHashCode];
supporter.Reset();
}
if(this.CanShrink())

{
this.Shrink();
}
}
}
//能够收缩对象池
privateboolCanShrink()

{
intidleCount=this.GetIdleObjCount();
intbusyCount=this.CurObjCount-idleCount;
return(busyCount<this.shrinkPoint)&&(this.CurObjCount>(this.minObjCount+(this.maxObjCount-this.minObjCount)/2));
}
privatevoidShrink()

{
while(this.CurObjCount>this.minObjCount)

{
intdestKey=-1;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])

{
destKey=key;
break;
}
}
if(destKey!=-1)

{
this.DistroyOneObject(destKey);
}
else

{
break;
}
}
if(this.PoolShrinked!=null)

{
this.PoolShrinked();
}
}
#endregion
publicvoidDispose()

{
TypesupType=typeof(System.IDisposable);
if(supType.IsAssignableFrom(this.destType))

{
ArrayListlist=(ArrayList)this.keyList.Clone();
foreach(intkeyinlist)

{
this.DistroyOneObject(key);
}
}
this.hashTableStatus.Clear();
this.hashTableObjs.Clear();
this.keyList.Clear();
}

property#regionproperty
publicintMinObjCount

{
get

{
returnthis.minObjCount;
}
}
publicintMaxObjCount

{
get

{
returnthis.maxObjCount;
}
}
publicintCurObjCount

{
get

{
returnthis.keyList.Count;
}
}
publicintIdleObjCount

{
get

{
lock(this)

{
returnthis.GetIdleObjCount();
}
}
}
privateintGetIdleObjCount()

{
intcount=0;
foreach(intkeyinthis.keyList)

{
if((bool)this.hashTableStatus[key])

{
++count;
}
}
returncount;
}
#endregion
#endregion
}
#endregion
}
博客围绕C#开发展开,提到某些对象创建耗时、体积大且需频繁创建/销毁,为省事要实现万能对象池组件,可缓存任意类型对象。还指出若缓存对象需维持客户状态,实现特定接口后,对象池收到归还对象时可重置其状态,并给出实现代码。
678

被折叠的 条评论
为什么被折叠?



