Работа со статическим классом в динамически загружаемой сторонней сборке - PullRequest
2 голосов
/ 26 августа 2011

Я нахожусь в ситуации, когда мне нужно использовать неподписанную стороннюю .NET DLL в моем подписанном приложении. Поэтому я решил загрузить эту библиотеку динамически во время выполнения:

var asm = Assembly.LoadFrom("THIRDPARTYASSEMBLY.DLL");

В DLL есть статический класс, для которого я определил интерфейс в своем приложении и использовал GetUninitializedObject() для загрузки класса:

var obj = FormatterServices.GetUninitializedObject(asm.GetType("NAMESPACE.CLASS")) as IMyInterface;

Хотя класс, который я пытаюсь загрузить, не является абстрактным (это класс public static), я получаю эту ошибку во время выполнения:

Исключение System.MemberAccessException не обработано: невозможно создать абстрактный класс.

Очевидно, я не могу использовать метод CreateInstance, потому что у статического класса нет конструкторов.

Так что бы вы предложили? Я хочу:

  • Вызвать метод public static из этой библиотеки. (Я сейчас использую InvokeMember().)
  • Получить Custom Type собственность.
  • Обработка нескольких Custom Events в моем приложении.

Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 26 августа 2011

Вместо того, чтобы пытаться вызывать метод динамически, вы можете попытаться дать строгое имя третьей стороне dll.

Вам понадобится ключ для строгого имени DLL. Вы можете использовать тот, который вы уже используете для своей собственной библиотеки DLL, или создать новый для этой цели (используя sn -k).

К строгому названию уже скомпилированной сборки:

  1. Откройте командную строку Visual Studio (чтобы получить инструменты на вашем пути).
  2. Генерация il из сборки:
    ildasm ThirdParty.dll /out:ThirdParty.il
  3. Переименуйте оригинальный файл ThirdParty.dll во что-то другое.
  4. Создайте новый dll, называя его сильным образом:
    ilasm ThirdParty.il /dll /key=MyKey.snk

Это приведет к новому ThirdParty.dll, который будет иметь строгое имя с указанным вами ключом. Затем вы можете добавить к нему прямую ссылку и вызвать методы напрямую, как обычно.

4 голосов
/ 26 августа 2011

Вам не нужен неинициализированный объект, если это просто статический класс.После того, как вы получили тип, например,

Type t = asm.GetType("NAMESPACE.CLASS");

, вы можете получить необходимые методы с помощью

MethodInfo method = t.GetMethod("MethodName");
//getmethod has some useful overloads
//also GetMethods() returns a MethodInfo[] array containing all methods

, затем вы можете позвонить

object result = method.Invoke(null, new object[] { param1, param2, ... } );

Есть другиеспособы сделать это также.Вы можете использовать делегаты для получения указателя функции на метод вместо вызова invoke.

Я не уверен, как делать обработчики событий, хотя я уверен, что если вы просматриваете intellisense под объектом Type, вы должны бытьв состоянии найти что-то.Что касается свойств, обычно вы используете их только для объектов, но если вы хотите использовать свойства статического класса и заранее знаете тип возвращаемого значения, вы можете создать класс для его обработки:

public class ExternalProperty<PropertyType>
{
    delegate PropertyType GetFunction();
    delegate void SetFunction(PropertyType value);
    GetFunction GetValue;
    SetFunction SetValue;

    public ExternalProperty(PropertyInfo externalProperty)
    {
        MethodInfo getMethod = externalProperty.GetGetMethod();
        GetFunction getter = (GetFunction)Delegate.CreateDelegate(typeof(GetFunction), getMethod);
        MethodInfo setMethod = externalProperty.GetSetMethod();
        SetFunction setter = (SetFunction)Delegate.CreateDelegate(typeof(SetFunction), setMethod);
    }

    public PropertyType Value
    {
        get { return GetValue(); }
        set
        {
            SetValue(value);
        }
    }
}

использовать этот класс очень просто, если вы уже знаете тип свойства.Допустим, у вас есть свойство Имя типа string:

ExternalProperty<string> PropName = new ExternalProperty(t.GetProperty("Name"));
string oldName = PropName.Value; //this will call the property's getter
PropName.Value = "new name"; //this will call the property's setter

, однако оно не проверяет ошибки, поэтому, если вы попытаетесь передать свойство другого типа, чем вы указали, или свойство, которое не может быть найдено дляэто сломается.Это также не работает для объектов, только для статических классов.Надеюсь, это поможет.

...