簡體   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