If you're unable to modify and recompile the library, have a look at ImpromptuInterface.
https://www.nuget.org/packages/ImpromptuInterface/
Example:
namespace ImpromptuExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Get the desired type
Type typeObject = typeof(SampleLibrary.PublicClass).Assembly.GetType("SampleLibrary.SamplePrivateClass");
// todo: add error handling if typeObject is null
// Create an instance
object instance = Activator.CreateInstance(typeObject);
ITest wrappedInstance = ImpromptuInterface.Impromptu.ActLike(instance);
MessageBox.Show(wrappedInstance.TestMethod(textBox1.Text));
}
public interface ITest
{
string TestMethod(string name);
}
}
}
namespace SampleLibrary
{
public class PublicClass
{
}
class SamplePrivateClass
{
public string TestMethod(string name)
{
return string.Concat("Hello ", name);
}
}
}
Internally, what ImpromptuInterface does is to create a dynamic assembly in memory and within that assembly, it creates a proxy class which implements the requested interface(s) and relays method calls and properties between the two. In the back end it still uses reflection but it is a slightly nicer encapsulation than doing it all through your own reflection.
Obviously there is an overhead involved with this but it is a viable last resort if you have no other option.
Useful features, include: the dynamic proxy class maps properties to fields, you can map interface methods to private, protected and internal methods in the original class. It doesn't work with static classes of methods, however.