【问题标题】:Cloning a Class Definition (PCL)克隆类定义 (PCL)
【发布时间】:2016-10-01 16:24:49
【问题描述】:

问题: 这可以使用反射克隆类定义吗?我不是在谈论浅层克隆或深层克隆。我说的是定义克隆。我想要一个带有静态变量的类,而不是在所有实例之间共享,而只是我创建的定义。而且我(或库)需要能够在以后从这个类创建一个实例。

问题: 你看,我需要这个是因为下面的场景,

有这个库希望我为它提供具有某种静态方法的类型。但是,在我的情况下,此静态方法需要比较来自另一种类型的非静态字段的两个值。这使得无法将具有信息的实例传递给类,因为它尚未初始化。查看以下情况示例:

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.iOSNSUrlProtocol 类,特别是CanInitWithRequest 方法。

可能的解决方案:经过更多思考,我发现解决这个问题的另一种方法是使StaticClass泛型;这样做可以让我每个type 定义都有一个静态变量。但是,要使其正常工作,我需要能够在运行时创建唯一且可能为空的类型。这可能吗?

XAMARIN.iOS: 不幸的是,Reflection.Emit 在 iOS 上不可用,所以现在我不认为这是可能的。仍在等待您的cmets了解情况。

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

【问题讨论】:

  • SOMELIBRARY 究竟对那个 StaticClass 做了什么?
  • @Evk:它会在创建类的新实例之前尝试调用CanCreate 方法,以查看该类是否可以处理该特定情况。
  • 为什么 CanCreate 是静态方法?那是那个图书馆的要求吗?
  • 如果在注册 StaticClass 之前,您将当前 MasterClass 设置为某个静态变量怎么办?例如,MasterClass.Current = this; SOMELIBRARY.RegisterType(typeof(StaticClass));?

标签: c# reflection portable-class-library redefinition


【解决方案1】:

有很多方法可以在运行时创建一个类,这似乎是您所要求的。你的问题似乎已经排除了System.Reflection.Emit,所以你可能想探索some of the other answers on this topic,看看它们是否适合你的平台(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 映射到 Handler1masterB 映射到 Handler2,依此类推。

【讨论】:

  • [抱歉英语不好] 谢谢你的回答,但在这种情况下,必须在设计时定义处理程序类。我正在寻找可以在运行时创建的解决方案。我够清楚了吗?
  • 感谢您的回答,经过很长时间:),不幸的是,似乎没有办法在运行时使用 XAMARIN.iOS 定义类。即使它看起来像是一种代码味道,但这更像是缩进功能的不兼容。 Apple 设计了 ​​API 来通过静态请求处理程序处理请求,但是,我的实现需要基于实例的检查。不幸的是,在您的示例中,您遵循了与 Apple 相同的方式并预先定义了类。我不知道我可能需要多少节课,一节、两节或一百节。所以我无法在代码中定义它们。
【解决方案2】:

经过大量搜索,我发现在 Xamarin.iOS 下甚至无法在 C# 中创建一个空类型,因此我不得不更改我的代码以符合 Apple API 的期望。

就我而言,我最终保留了MasterClass 的所有实例的列表以在StaticClass 中使用;构造函数和静态方法都通过列表并将所需的MasterClass 与请求匹配。这里有一个风险,这样做会导致内存泄漏,因为MasterClass 的实例永远不会被收集,但就我而言,这不是问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 2015-03-27
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多