简体   繁体   English

如何在基类中实现通用的 Save() 函数

[英]How to Implement a general Save() Function in a Base Class

As an assessment, I received the following Testcase so I can implement the code behind:作为评估,我收到了以下测试用例,以便我可以实现背后的代码:

[TestCase]
public void ProgrammerTest() 
{
    var address = new Address("56 Main St", "Mesa", "AZ", "38574");
    var customer = new Customer("John", "Doe", address);
    var company = new Company("Google", address);
 
    Assert.IsNullOrEmpty(customer.Id);
    customer.Save();
    Assert.IsNotNullOrEmpty(customer.Id);
 
    Assert.IsNullOrEmpty(company.Id);
    company.Save();
    Assert.IsNotNullOrEmpty(company.Id);
 
    Customer savedCustomer = Customer.Find(customer.Id);
    Assert.IsNotNull(savedCustomer);
    Assert.AreSame(customer.Address, address);
    Assert.AreEqual(savedCustomer.Address, address);
    Assert.AreEqual(customer.Id, savedCustomer.Id);
    Assert.AreEqual(customer.FirstName, savedCustomer.FirstName);
    Assert.AreEqual(customer.LastName, savedCustomer.LastName);
    Assert.AreEqual(customer, savedCustomer);
    Assert.AreNotSame(customer, savedCustomer);
 
    Company savedCompany = Company.Find(company.Id);
    Assert.IsNotNull(savedCompany);
    Assert.AreSame(company.Address, address);
    Assert.AreEqual(savedCompany.Address, address);
    Assert.AreEqual(company.Id, savedCompany.Id);
    Assert.AreEqual(company.Name, savedCompany.Name);
    Assert.AreEqual(company, savedCompany);
    Assert.AreNotSame(company, savedCompany);
 
    customer.Delete();
    Assert.IsNullOrEmpty(customer.Id);
    Assert.IsNull(Customer.Find(customer.Id));
 
    company.Delete();
    Assert.IsNullOrEmpty(company.Id);
    Assert.IsNull(Company.Find(company.Id));
}

The requirements are:要求是:

  • In C# create a single class that when subclassed allows this sample test code to run using only the file system for storage, no pre-built database allowed;在 C# 中创建一个类,当子类化时,该类允许此示例测试代码仅使用文件系统进行存储运行,不允许使用预构建的数据库; use files.使用文件。
  • Create all classes required to compile and pass the test case;创建编译和通过测试用例所需的所有类; you may not modify the test.您不得修改测试。 The test is not wrong, it's not a trick.测试没有错,它不是一个伎俩。
  • The Id , Save , Delete , and Find methods must be in the super class only; IdSaveDeleteFind方法必须仅在超类中; subclasses must not implement these methods themselves.子类不能自己实现这些方法。

Here are a class example I could extract from the test cases:这是我可以从测试用例中提取的一个类示例:

public abstract class MyBase
{
    public abstract void Save();
    public abstract void Delete();
}

public class Company : MyBase
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }

    public Company(string name, Address address)
    {
        this.Name = name;
        this.Address = address;
    }

    internal static Company Find(string id)
    {
        throw new NotImplementedException();
    }

    public override void Delete()
    {
       throw new NotImplementedException();
    }

    public override void Save()
    {
        object company = new List<Company>();

        if (company != null)
        {
            // serialize JSON to a string and then write string to a file
            File.WriteAllText(@"c:\company.json", JsonConvert.SerializeObject(company));
        }
    }
}

I have experience creating TestCases for a given code, but not the other way out and I could extract the Classes from it but, how can I implement the methods Save() , Delete() , Find(customer.Id) as Generic Types without passing the populated data classes?我有为给定代码创建 TestCases 的经验,但不是另一种方法,我可以从中提取类,但是,如何将方法Save()Delete()Find(customer.Id)为通用类型,而无需传递填充的数据类? I know I could do something like void Save(object obj) and implement the passed object on the Base, but the testcase just calls like customer.Save() ... So, how can I do this?我知道我可以做一些类似void Save(object obj)事情并在 Base 上实现传递的对象,但测试用例只是像customer.Save()一样调用......那么,我该怎么做呢?

Thanks in advance for any input!提前感谢您的任何意见!

I would assume the intent is to use some kind of serialization to produce a copy of the object.我认为目的是使用某种序列化来生成对象的副本。

Json杰森

If using json.net you should be able to use name-handling to include the actual object type in the serialized message:如果使用 json.net,您应该能够使用名称处理在序列化消息中包含实际对象类型:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
};

string strJson = JsonConvert.SerializeObject(instance, settings);

From how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET如何使用 Newtonsoft JSON.NET 将 JSON 反序列化为 IEnumerable

Protobuf原缓冲区

You could also use a protobuf.net with ProtoInclude to allow it to serialize subtypes:您还可以将protobuf.net与 ProtoInclude 一起使用,以允许它序列化子类型:

[ProtoContract]
[ProtoInclude(7, typeof(SomeDerivedType))]
class SomeBaseType {...}

[ProtoContract]
class SomeDerivedType {...}

Then the base-type should just be able to serialize this to a memory-stream and deserialize it again, store the copy in a static list, and let the find method search the list.那么基本型应该只能够序列化this到一个内存流和再次反序列化,存储在静态列表中的副本,让find方法搜索列表。

Protected virtual/abstract members受保护的虚拟/抽象成员

Another approach would be to just add protected virtual methods to the sub-types to do all the actual work of creating an identical object.另一种方法是向子类型添加protected virtual方法,以完成创建相同对象的所有实际工作。 The task only specified that the Save method needs to be on the base type, not that it needs to do the actual work without help from the sub-type.该任务仅指定Save方法需要在基类型上,而不是需要在没有子类型帮助的情况下执行实际工作。

Note that I would not recommend the practices from that assignment due to several issues:请注意,由于以下几个问题,我不会推荐该作业中的做法:

  • The simplest way to pass the test is with static mutable fields, and these are generally not recommended.通过测试的最简单方法是使用静态可变字段,通常不推荐使用这些方法。
  • Using serialization to produce deep copies might be appropriate in some cases, but I would generally recommend against it.在某些情况下,使用序列化来生成深拷贝可能是合适的,但我通常建议不要这样做。 Reason is that not all types would be expected to be serializable, and that deep copies might be expected to be fairly cheep to construct.原因是并非所有类型都应该是可序列化的,并且深度副本的构建成本可能相当低。
  • The instructions suggest that writing to files are expected.说明建议写入文件。 Unit tests should in general avoid writing to disk since disk is comparably slow, and unit tests need to run fast to be useful.单元测试通常应该避免写入磁盘,因为磁盘相对较慢,并且单元测试需要快速运行才能有用。
  • I find it fairly rare for copies to be needed.我发现需要副本的情况相当罕见。 In many cases, immutable objects are easier to use, and does not need to be copied.在很多情况下,不可变对象更易于使用,并且不需要复制。
  • The test seem rather nonsensical overall.总体而言,该测试似乎相当荒谬。 If I saw that in the wild it would trigger quite a few WTFs.如果我在野外看到它会触发很多 WTF。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM