/*
com组件,object对象释放,
ref: https://www.codenong.com/2191489/
using (var coms = new ReleaseWrapper())
{
var fso = coms.Add(new FileSystemObject());
var dir1 = coms.Add(() => new FileSystemObject().Drives["c"].RootFolder);
}
*/
class ReleaseWrapper : IDisposable
{
readonly List<object> m_Coms = new List<object>();
readonly List<IDisposable> m_NetObjs = new List<IDisposable>();
public T Add<T>(Expression<Func<T>> func)
{
return (T)Walk(func.Body);
}
public T Add<T>(T obj)
{
if (obj != null)
{
if (Marshal.IsComObject(obj))
{
m_Coms.Add(obj);
}
else
{
IDisposable iDis = obj as IDisposable;
if (iDis != null)
{
m_NetObjs.Add(iDis);
}
}
}
return obj;
}
object Walk(Expression expr)
{
return WalkImpl(expr);
}
object[] Walk(IEnumerable<Expression> args)
{
if (args == null) return null;
return args.Select(arg => Walk(arg)).ToArray();
}
object WalkImpl(Expression expr)
{
Debug.WriteLine(expr?.NodeType);
//Debug.WriteLine(expr.ToString());
switch (expr.NodeType)
{
case ExpressionType.Constant:
return ((ConstantExpression)expr).Value;
case ExpressionType.New:
NewExpression ne = (NewExpression)expr;
return ne.Constructor.Invoke(Walk(ne.Arguments));
case ExpressionType.MemberAccess:
MemberExpression me = (MemberExpression)expr;
object target = Walk(me.Expression);
switch (me.Member.MemberType)
{
case MemberTypes.Field:
return ((FieldInfo)me.Member).GetValue(target);
case MemberTypes.Property:
return Add(((PropertyInfo)me.Member).GetValue(target, null));
default:
throw new NotSupportedException();
}
case ExpressionType.Call:
{
MethodCallExpression mce = (MethodCallExpression)expr;
object obj;
if (mce.Object == null)
{
obj= mce.Method.Invoke(mce.Object, Walk(mce.Arguments));
}
else
{
obj= mce.Method.Invoke(Walk(mce.Object), Walk(mce.Arguments));
}
return Add(obj);
}
case ExpressionType.Convert:
{
UnaryExpression uex = expr as UnaryExpression;
object obj = Walk(uex.Operand);
if (obj as IConvertible == null)
{
return obj;
}
else
{
return Convert.ChangeType(obj, uex.Operand.Type);
}
}
default:
throw new NotSupportedException();
}
}
public void Dispose()
{
Debug.WriteLine($"Com Count:{m_Coms.Count}");
for (int i = m_Coms.Count - 1; i >= 0; i--)
{
Marshal.ReleaseComObject(m_Coms[i]);
//Debug.WriteLine("Released:" + m_Coms[i]);
}
m_Coms.Clear();
for (int i = m_NetObjs.Count - 1; i >= 0; i--)
{
m_NetObjs[i].Dispose();
}
m_NetObjs.Clear();
}
}