C# version of C++ shared_ptr
public SharedDisposable(object[] ctorArgs = null)
{
  if (ctorArgs == null)
      ctorArgs = new object[] { };

  var ctor = typeof(SharedDisposable&lt;T&gt;).GetConstructor(ctorArgs.Select(a =&gt; a.GetType()).ToArray());
  Item = (T)ctor.Invoke(ctorArgs);
  instances[Item] = new List&lt;SharedDisposable&lt;T&gt;&gt;() { this };
}



This constructor is not a very good idea because the use needs to exactly know the signature of the constructor in order to create T.

A much better way would be to let him specify a factory lambda. Then all it will be left is:

public SharedDisposable(Func&lt;T&gt; create)
{
    Item = create();
    instances[Item] = new List&lt;SharedDisposable&lt;T&gt;&gt;() { this };
}


so now he can call it in a much easier fashion like:

Port = new SharedDisposable&lt;SerialPort&gt;(() =&gt; new SerialPort("COM5", 9600));


The other constructor using KeyValuePairs is now obsolete.




public SharedDisposable(object[] ctorArgs = null)
{
  if (ctorArgs == null)
      ctorArgs = new object[] { };
  ...
}



Btw. you can make this look cleaner with the coalesce operator: ??

ctorArgs = ctorArgs ?? new object[] { };




Objects like this one usully use the name Value for what you chose Item.



Its usage might be easier in certain scenarios if you added an implicit cast operator to T:

public static implicit operator T(SharedDisposable&lt;T&gt; share) =&gt; share.Value;




If you replaced the List by a HashSet the Dispose method could be simplified to:

public void Dispose()
{
    if (instances[Value].Remove(this) &amp;&amp; instances[Value].Count == 0)
    {
        instances.Remove(Value);
        Value.Dispose();
    }
}