如何使用参数化构造函数实现保存/加载接口?

发布于 2024-10-30 05:45:11 字数 583 浏览 3 评论 0原文

我知道接口不能定义构造函数。这是我希望我能做的:

public interface SavableObject {
    void Save(ObjectSaver saver);
    SavableObject(ObjectLoader loader); //This, obviously, doesn't work
}


//Loading an object inside ObjectLoader:
T LoadObject<T>() where T : SavableObject  {
    return (T)Activator.CreateInstance(typeof(T), this);
}

如果我取出不起作用的行,并且在尝试加载时只会出现运行时错误(或者可能保存,如果我在其中放置断言)对象(如果没有构造函数)。我只是想知道是否有任何方法要求一个类具有可与激活器一起使用的特定构造函数。我可以以某种方式使用自定义属性,并要求该属性位于类中吗?或者我必须依赖运行时检查来加载和保存数据?

我知道我可以有一个无参数构造函数和一个 Load(ObjectLoader) 方法,但我不一定希望有一个无参数构造函数可用于其他目的。

I know interfaces cannot define constructors. Here's what I wish I could do:

public interface SavableObject {
    void Save(ObjectSaver saver);
    SavableObject(ObjectLoader loader); //This, obviously, doesn't work
}


//Loading an object inside ObjectLoader:
T LoadObject<T>() where T : SavableObject  {
    return (T)Activator.CreateInstance(typeof(T), this);
}

And I could do this if I took out the line that didn't work, and there would just be a runtime error when trying to load (or possibly save, if I put an assert in there) the object if it didn't have the constructor. I'm just wondering if there's any way to require a class to have a particular constructor that can be used with the Activator. Can I use a custom attribute somehow, and require that attribute to be on the class? Or must I rely on runtime checks to load and save data?

I know I could have a parameterless constructor and a Load(ObjectLoader) method but I don't necessarily want to have a parameterless constructor available to abuse for other purposes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

森末i 2024-11-06 05:45:11

ISerialized 怎么样?

what about ISerializable?

掀纱窥君容 2024-11-06 05:45:11

简而言之,我建议您像大多数工厂一样使用泛型

public interface SavableObject<T> : where T : new
{
    void Save(IObjectSaver<T> saver);
    SavableObject<T> Load(ObjectLoader loader); //This, obviously, doesn't work
}

然而,你似乎已经把它颠倒过来了。 该类正在做工厂必须做的事情。所以我认为将工厂传递给实体本身并不是一个好主意,这是您在设计。

In brief I suggest you use generics as most factories do.

public interface SavableObject<T> : where T : new
{
    void Save(IObjectSaver<T> saver);
    SavableObject<T> Load(ObjectLoader loader); //This, obviously, doesn't work
}

However, you seem to have turned it on it head. The class is doing what factory must do. So I do not think it is such a good idea to pass the factory to the entity itself and that is part of the problem you are experiencing in the design.

街角迷惘 2024-11-06 05:45:11

如果您不害怕使用反射,就像您所展示的 Activator 一样,您可以做一些我倾向于使用的小技巧:

  1. 制作受保护的无参数构造函数
  2. ,使 Load 方法也受保护(或私有,我倾向于使用虚拟受保护)所以我支持继承)
  3. 使用这个非公共构造函数创建新对象(通过反射 - 你不能使用 new 运算符“就像那样”创建类的实例)
  4. 调用加载方法(也使用反射 - 以后没有人会调用它)。

我不知道这是否适合您,但是当我需要反序列化相当大的游戏状态时,我使用了该方法,并且速度非常快,尽管所有这些反射(由于多种原因,我不想使用内置序列化)方法和工厂模式不会这样做,所以我倾向于将此方法视为在其他方法失败时可能有用的方法,另一方面,如果可以的话 - 为了简单起见,我可能会使用内置序列化)。

If you are not afraid of using Reflection, like Activator that you have shown, you can do little trick I tend to use:

  1. Make parameterless constructor that is protected
  2. Make Load method, that is also protected (or private, I tend to use virtual protected so I support inheritance)
  3. Create new object using this non-public constructor (through reflection - you can't create instance of your class "just like that" using new operator)
  4. Invoke load method (also using reflection - no one will call it later).

I don't know if this will work for you, but I used that method when I needed to deserialize pretty big game state and it was pretty fast, eventhough all this reflection (for many reasons I did not wanted to use built-in serialization methods and Factory Pattern wouldn't do, so I tend to treat this method as something that may be useful if other methods fail, on the other hand, if I could - I would probably use built-in serialization for simplicity).

叶落知秋 2024-11-06 05:45:11

如何在您的界面上添加属性:

public interface SavableObject 
{
    void Save(ObjectSaver saver);
    ObjectLoader ObjectLoader {get; set;}
}

然后在您的工厂中:

T LoadObject<T>() where T : SavableObject  
{
    var result = (T)Activator.CreateInstance(typeof(T));
    result.ObjectLoader = this;
    return result;
}

How about adding a property on your interface:

public interface SavableObject 
{
    void Save(ObjectSaver saver);
    ObjectLoader ObjectLoader {get; set;}
}

Then in your factory:

T LoadObject<T>() where T : SavableObject  
{
    var result = (T)Activator.CreateInstance(typeof(T));
    result.ObjectLoader = this;
    return result;
}
2024-11-06 05:45:11

根据您的问题和评论。

我认为你应该在运行时使用反射来完成它。

将构造函数和接口结合起来从其核心来看是不合逻辑的。接口是关于具体实例可以做什么,而不是如何初始化它。这只能使用抽象类来实现。

也许使用工厂来创建类的实例?

另外,我认为您无法获得比默认 ISerialized 实现更好的速度。除非您是 .NET GURU 并且有多年的时间。

Based on your question and comments.

I think you should do it at runtime using reflection.

Combining constructors and interfaces is ilogical from its core. Interface is about what concrete instance can do, not how to initialize it. This can only be achived using abstract class.

Maybe using factory to create instance of the class?

Also I don't think you can get better speed than default ISerializable implementation. Unless you are .NET GURU and have years of time for it.

愿得七秒忆 2024-11-06 05:45:11

简短的回答:我想这是不可能的。我没有可以使用任何属性或概括来要求类上有特定类型的构造函数。

Short answer: It's not possible, I guess. There are no attributes or generalizations I can use to require a specific kind of constructor on a class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文