繁体   English   中英

C#中静态方法的模板

[英]A Template for Static Methods in C#

我正在编写一个允许用户运行测试的应用程序。 测试由许多不同的对象组成,例如配置,温度和基准。 设置等在xml之间来回保存。 我在代码中传递了不同的XElements,因此我可以针对不同的情况以不同方式构建最终的xml文档。 我希望做这样的事情:

public abstract class BaseClass<T>
{
    abstract static XElement Save(List<T>);
    abstract static List<T> Load(XElement structure);
}

public class Configuration : BaseClass<Configuration>
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    //etc...

    public static XElement Save(List<Configuration>)
    {
        XElement xRoot = new XElement("Root");
        //etc...
        return xRoot;
    }

    public static List<Configuration> Load(XElement structure)
    {
        List<BaseClass> list = new List<BaseClass>();
        //etc...
        return list;
    }
}

public class Temperature : BaseClass<Temperature>
{
    public float Value { get; set; }

    public static XElement Save(List<Temperature>)
    {
        //save
    }

    public static List<Temperature> Load(XElement structure)
    {
        //load
    }
}

[编辑]:修改问题(更改上述职能的签名)[/ EDIT]

当然,我实际上不允许覆盖BaseClass的静态方法。 解决这个问题的最佳方法是什么? 我希望以下内容尽可能有效:

List<Temperature> mTemps = Temperature.Load(element);
List<Configuration> mConfigs = Configuration.Load(element);

Temperature.Save(mTemps);
Configuration.Save(mConfigs);

[编辑]更改了[/ EDIT]上方的预期用法代码

我能想到的唯一解决方案是以下,这是不可接受的:

public class File
{
    public static XElement Save(List<Temperature> temps)
    {
        //save temp.Value
    }

    public static XElement Save(List<Configuration> configs)
    {
        //save config.Property1
        //save config.Property2
    }

    //etc...
}

静态方法不是类实例的一部分。 无论如何,压倒它们都没有任何意义。 他们无法访问他们恰好是其成员的实例的任何非静态部分。

这是一种策略模式场景,例如,您可以使用单个静态Load&Save方法来检查传递给它们的对象的类型,并采取相应的行动。 但是,这是另一种更聪明的方法,它使用泛型类型来创建原型并调用其方法,允许您将逻辑保留在每个派生对象类型中。

(再次编辑)

这是另一个裂缝,与我原来的建议一样。 我实际测试了它并且它可以工作,所以我认为这是你能做的最好的事情来获得你正在寻找的所有功能(除了测试类型和有条件地调用代码)。 您仍然需要为Load传递一个类型,否则,运行时将不知道期望什么样的返回。 但是Save普遍适用。 子类实现是强类型的。

这只是使用列表中的第一个对象作为其原型,足够简单。

public interface IBaseObject 
{
    XmlElement Save(IEnumerable<IBaseObject> list);
    IEnumerable<IBaseObject> Load(XmlElement element);
}
public interface IBaseObject<T> where T: IBaseObject 
{
    XmlElement Save(IEnumerable<T> list);
    IEnumerable<T> Load(XmlElement element);
}

public class Temperature : IBaseObject<Temperature>, IBaseObject 
{

    public XmlElement Save(IEnumerable<Temperature> list)
    {
        throw new NotImplementedException("Save in Temperature was called");
    }

    public IEnumerable<Temperature> Load(XmlElement element)
    {
        throw new NotImplementedException("Load in Temperature was called");
    }

    // must implement the nongeneric interface explicitly as well

    XmlElement IBaseObject.Save(IEnumerable<IBaseObject> list)
    {
        return Save((IEnumerable<Temperature>)list);
    }

    IEnumerable<IBaseObject> IBaseObject.Load(XmlElement element)
    {
        return Load(element);
    }
}

// or whatever class you want your static methods living in

public class BaseObjectFile
{
    public static XmlElement Save(IEnumerable<IBaseObject> list)
    {
        IBaseObject obj = list.DefaultIfEmpty(null).First();  // linq
        return obj==null ? null : obj.Save(list);
    }
    public static IEnumerable<IBaseObject> Load<T>(XmlElement element) 
        where T: IBaseObject, new()
    {
        IBaseObject proto = new T();
        return proto.Load(element);
    }
}

(原始编辑)

这有一个问题,你必须用类型调用静态方法,例如

BaseClass<Temperature>.Load()

对于Save方法有一种解决方法,但是你想要的部分是不可能的。 Load方法无法知道要返回的列表类型,因为它的唯一参数没有关于返回类型的信息。 因此,它不可能决定创建哪种类型作为原型。 所以无论如何,如果你想使用常见的Load方法,你必须传递类似上面语法的类型。

对于Save方法,您可以使用反射在静态方法中创建原型,方法是从第一个元素获取类型,然后从原型中调用Save方法。 因此,如果您只需要使用Save方法,那么就可以实现。

但最终,我认为做这样的事情要简单得多:

public static XElement Save(List<IBaseClass> list)
{       
    if (list is Temperature) {
       // do temperature code
    } else if (list is SomethingElse) {
      // do something else
    } 
}

无论如何 - 就像我说它需要反射才能使Save方法以这种方式工作。 我只是使用简单的方法。

(删除原始错误代码)

如果你真的不关心它保存的格式,你可以自由使用序列化(内部使用反射)。

string SerialiseToString<T>(T source)
{
    using (StringWriter sw = new StringWriter() && XmlSerializer xml = new XmlSerializer(typeof(OrderedItem)))
    {
        xml.Serializer(sw, source);
        return sw.ToString();
    }
}

如果要将其合并到XML文件的更大部分中,最简单的方法是解析此输出并将其添加到您的输出中。 或者,您可以自己反映属性。

如果共享部分相同,您可以将它放在BaseClass

public static XElement Save(IEnumerable<BaseClass> list)
{
    var root = new XElement("root");
    foreach (var item in list)
    {
        item.Save(root);
    }
    return root;
}

这里, Save(XElement)是一个虚方法,每种类型都实现它。

显然,您不能通过加载来执行此操作,您要么必须知道要加载的是哪种类型,要么找到一些方法来查找要加载的类型。

暂无
暂无

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

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