Клонирование определения класса (PCL)

Вопрос: Можно ли клонировать определение класса с помощью отражения? Я не говорю о мелком или глубоком клонировании. Я говорю о клонировании определений. Я хочу иметь класс со статической переменной, не разделяемой между всеми экземплярами, а только созданное мной определение. И мне (или библиотеке) нужно иметь возможность создать экземпляр из этого класса позже.

Проблема: Видите ли, мне это нужно из-за следующего сценария,

Есть эта библиотека, которая ожидает, что я предоставлю ей тип, имеющий определенный статический метод. Однако в моем случае этот статический метод должен сравнить два значения, одно из нестатического поля другого типа. Это делает невозможным передачу экземпляра, содержащего информацию, в класс, поскольку он еще не инициализирован. Посмотрите на следующий пример ситуации:

class MasterClass 
{
    public int SomeInfo {get; set;} = 10;
    public void PeresentClass()
    {
        SOMELIBRARY.RegisterType(typeof(StaticClass));
    }
}
class StaticClass
{
    public static bool CanCreate(int someVar)
    {
        // I need to compare someVar with the SomeInfo property of MasterClass instance that presented this type to the SOMELIBRARY.
    }
    public StaticClass()
    {
        // Something irrelevant
    }
}

В приведенном выше примере я не могу контролировать SOMELIBRARY и то, как они решили написать код. Но кажется, что они каким-то образом хотят сначала вызвать метод CanCreate, а затем создать экземпляр класса, если он соответствует требованиям.

Однако для правильной работы CanCreate мне необходимо иметь доступ к экземпляру класса, который в первую очередь представляет StaticClass SOMELIBRARY. И я не могу сделать MasterClass статическим, потому что каждый раз активным является более одного экземпляра этого класса.

Единственный способ, который я мог придумать, - это переопределить новый StaticClass со статическим полем, указывающим на MasterClass, который его определил (или клонировал определение). Однако мои знания рефлексии пока не позволяли мне этого сделать. Итак, я спрашиваю, возможно ли это вообще? И мне бы очень хотелось иметь возможность делать это в профилях PCL.

Реальный мир: для получения дополнительной информации я говорю о классах XAMARIN.iOS и NSUrlProtocol, особенно о методе CanInitWithRequest.

Возможное решение. Поразмыслив, я обнаружил, что еще один способ решить эту проблему - сделать StaticClass общим; Это позволяет мне иметь статическую переменную согласно type определению. Однако для того, чтобы это работало, мне нужно иметь возможность создавать уникальные и, возможно, пустые типы во время выполнения. Это возможно?

XAMARIN.iOS: К сожалению, Reflection.Emit недоступен на iOS, поэтому пока я не верю, что это вообще возможно. Все еще жду ваших комментариев по ситуации.

https://developer.xamarin.com/guides/ios/advanced_topics/limitations/#System.Reflection.Emit


person Soroush Falahati    schedule 01.10.2016    source источник
comment
Что именно SOMELIBRARY делает с этим StaticClass?   -  person Evk    schedule 01.10.2016
comment
@Evk: он пытается вызвать метод CanCreate перед созданием нового экземпляра класса, чтобы узнать, может ли класс справиться с этой конкретной ситуацией.   -  person Soroush Falahati    schedule 01.10.2016
comment
А почему CanCreate - это статический метод? Это требование той библиотеки?   -  person Evk    schedule 01.10.2016
comment
Что, если перед регистрацией StaticClass вы установите для текущего MasterClass некоторую статическую переменную? Например, MasterClass.Current = this; SOMELIBRARY.RegisterType (typeof (StaticClass)) ;?   -  person Evk    schedule 01.10.2016
comment
@Evk, проблема в том, что существует более одного экземпляра MasterClass, и все они могут попытаться зарегистрировать StaticClass и заявить о его функциональности для себя.   -  person Soroush Falahati    schedule 01.10.2016
comment
@Evk, Видишь ли, каждый экземпляр MasterClass должен уметь работать индивидуально, или я мог бы просто сделать MasterClass статическим. Но это невозможно.   -  person Soroush Falahati    schedule 01.10.2016


Ответы (2)


Есть несколько способов создать класс во время выполнения, что похоже на то, о чем вы спрашиваете. Ваш вопрос, похоже, исключил System.Reflection.Emit, поэтому вы можете изучить некоторые других ответов по этой теме, чтобы узнать, подходят ли они для вашей платформы (Xamarin.IOS).

Тем не менее, ваш вопрос, похоже, указывает на запах кода в вашей реализации. Вы пытаетесь сопоставить экземпляр класса с функцией регистрации API, которая полагается на статический метод, чтобы указать пригодность ресурса для обработки типа запроса (canInitWithRequest). Эта функция должна только указывать, может ли зарегистрированный класс NSURLProtocol обрабатывать конкретный тип запроса, он, вероятно, не должен зависеть от некоторого свойства класса другого объекта в системе.

Лучше всего, если бы ваш NSURLProtocol экземпляр просматривал общий ресурс во время выполнения, когда он вызывается базовой структурой. Например, что-то вроде следующего:

static class SystemMap {
    // Store some mapping information in a commonly accessible system resource
    // In this case a simple static class that wraps up a dictionary
    static Dictionary<Type, Master> systemMap = new Dictionary<Type, Master>();

    // Allow registered components to be accessed
    public static Master getRegisteredMaster(Type handlerType) {
        return systemMap[handlerType];
    }

    // Allow new registrations to be made in your system
    public static void registerNewMaster(Master registrant, Type handlerType) {
        systemMap[handlerType] = registrant;
    }
}

class Master {
    // This would be your custom class that you instantiate throughout your system
    public string name;
    public int someVar { get; set; } = new Random().Next(1, 100);
    public Master(string name) {
        this.name = name;
    }
}

class BaseHandlerType {
    // This would be NSURLProtocol
}

class Handler1 : BaseHandlerType {
    // This would be canInitWithRequest
    public static bool CanCreate(int someVar) {
        Master myMaster = SystemMap.getRegisteredMaster(typeof(Handler1));
        return someVar > myMaster.someVar;
    }
}

class Handler2 : BaseHandlerType {
    //... Register various handler types to various "Master" instances in your system
    // This is a concrete implementation of NSURLProtocol
}

class Handler3 : BaseHandlerType {
    //... Register various handler types to various "Master" instances in your system
    // This is a concrete implementation of NSURLProtocol
}

class SystemFactory {
    // Use a factory method to instantiate the system components and plug things together
    public void initializeSystem() {
        var masterA = new Master("a");
        var masterB = new Master("b");
        var masterC = new Master("c");
        SystemMap.registerNewMaster(masterA, typeof(Handler1));
        SystemMap.registerNewMaster(masterB, typeof(Handler2));
        SystemMap.registerNewMaster(masterC, typeof(Handler3));
        SomeLibrary.register(typeof(Handler1));
        SomeLibrary.register(typeof(Handler2));
        SomeLibrary.register(typeof(Handler3));
    }
}

static class SomeLibrary {
    public static void register(Type handlerType) {
        // This represents the API registration
    }
}

Этот шаблон может помочь вам установить отношения между компонентами, которых вы пытаетесь достичь с помощью создания класса во время выполнения. Этот шаблон позволит вашим различным типам обработчиков (т.е. NSURLProtocol классам) обращаться к другому Master экземпляру при их вызове. В этом примере masterA отображается на Handler1, masterB на Handler2 и так далее.

person Kin3TiX    schedule 06.07.2017
comment
[Извините за плохой английский] Спасибо за ответ, но в этом случае классы Handlers должны быть определены во время разработки. Я искал решение, которое могу создать во время работы. Достаточно ли ясно? - person Diego Rafael Souza; 06.07.2017
comment
Спасибо за ответ, спустя долгое время :) К сожалению, похоже, нет возможности определять классы во время выполнения с XAMARIN.iOS. И даже хотя это кажется запахом кода, но это скорее несовместимость в функциональных возможностях с отступом. Apple разработала API для обработки запросов через статический обработчик запросов, однако в моей реализации требовалась проверка на основе экземпляра. К сожалению, в вашем примере вы пошли по тому же пути, что и Apple, и заранее определили классы. Я не знаю, сколько классов мне может понадобиться - один, два или сто. Поэтому я не могу определить их в коде. - person Soroush Falahati; 07.07.2017

После долгих поисков я не нашел способа создать даже пустой тип на C # под Xamarin.iOS, и в результате мне пришлось изменить свой код, чтобы он соответствовал ожиданиям Apple API.

В моем случае я сохранил список всех экземпляров MasterClass для использования в StaticClass; и конструктор, и статический метод просматривают список и сопоставляют желаемый MasterClass с запросом. Здесь есть риск, что в результате вы получите утечку памяти, потому что экземпляры MasterClass никогда не будут собраны, но в моем случае это не было проблемой.

person Soroush Falahati    schedule 07.07.2017