【问题标题】:Alternative to being able to define static extension methods能够定义静态扩展方法的替代方法
【发布时间】:2010-02-24 09:16:48
【问题描述】:

我知道我不能在 C# 中扩展静态类,我不真的明白其中的原因,但我明白 它不可能完成。

因此,考虑到这一点,这就是我想要实现的目标:

public static class GenericXmlSerialisationExtender
{
    public static void WriteToXML<T>(this T targetObject, string fileName)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (TextWriter writer = new StreamWriter(fileName, false, Encoding.UTF8))
        {
            serializer.Serialize(writer, targetObject);
        }
    }

    public static T ReadFromXML<T>(string fileName)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (TextReader reader = new StreamReader(fileName, Encoding.UTF8))
        {
            return (T)serializer.Deserialize(reader);
        }
    }
}

即我想为实例定义 .WriteToXML(我需要使用很多配置/静态数据类,它们只使用 vanilla XML 序列化),然后为类型定义 .ReadFromXML。

如此有效,我可以这样称呼:

MyType typeInstance = MyType.ReadFromXML(path_to_data);

封装它的“正确”方式是什么?我曾经和一位同事一起工作,他认为“代码重用”是复制和粘贴,我宁愿不把自己放在那个括号里!

【问题讨论】:

    标签: c# generics serialization extension-methods


    【解决方案1】:

    您可以完全按照您已经完成的方式定义它,但要调用它,您将使用标准的静态方法调用:

    MyClass deserializedObject = GenericXmlSerialisationExtender.ReadFromXML<MyClass>(@"c:\filename.xml");
    

    (如果您这样做,您可能希望给您的 GenericXmlSerialisationExtender 类一个更合适的名称,或者将其移至不同的静态类)


    扩展方法不能在静态方法上工作的原因是没有对象也可以附加扩展方法。

    在你的例子中:

    public static T ReadFromXML<T>(string fileName)
    

    您在该行中没有定义您想要扩展的类型。扩展方法要求第一个参数是您希望扩展方法对其进行操作的对象。

    扩展方法只是语法糖,是创建静态辅助方法的好方法。

    在 .net 2.0 中你会写:

    public static class StringHelper
    {
        public static String AddFullStop(String data)
        {
            return data + ".";
        }
    }
    
    String input = "test";
    String output = StringHelper.AddFullStop(input);
    

    .net 3.5 让您能够做到这一点:

    public static class StringExtensions
    {
        public static String AddFullStop(this String data)
        {
            return data + ".";
        }
    }
    
    String input = "test";
    String output = input.AddFullStop();
    

    因此,当您想做一些超出便利扩展方法范围的事情时,您只需退回到旧的静态辅助方法模式即可。

    【讨论】:

    • 你说“没有对象可以附加扩展方法”——这是我理解的一点。为什么将其扩展为您建议的代码会是一个巨大的飞跃?不争论,只是想真正了解为什么...
    • @Matt:因为您没有在扩展方法签名中指定要扩展的“类型”。扩展方法会出现在哪种类型上? (这很好,在您的情况下,您实际上只是想扩展“对象”,但情况并非总是如此,您将如何告诉编译器您希望静态扩展方法出现在字符串上)。这将需要 C# 设计团队添加更多语法更改,以允许您指定要静态扩展的类型。
    • 我想 C# 团队可以实现这种新语法,但这是一个非常不寻常的情况。添加了扩展方法以支持非常常见的“静态助手类”模式。他们通常不会仅仅为了支持您建议的那种不寻常的边缘情况而进行语法更改。它实际上也不会为您带来任何可读性,编写 String.HelperMethod(); 之间没有太大区别。或 StringHelper.Method();
    • @Simon - 当然,如果你想限制方法可用的类型,你可以使用标准,并且已经定义了 where 约束 - 所以,对于字符串,只需使用 where T: String?
    • @Matt: "where T: String" is invalid - "string 不是有效的约束。用作约束的类型必须是接口、非密封类或类型参数。" - 此外,您假设您提出的“静态扩展”是通用的。它必须与您建议的语法一致。泛型有一些限制,例如不能调用约束接口中未定义的方法,这会导致许多其他问题。最后,这种形式的通用约束,只约束类型必须从 String 继承(如果允许的话),这在所有情况下都是不够的。
    【解决方案2】:

    我实际上并不是在推荐这个,而是作为一个选项

    public static T ReadFromXML<T>(this T ignored, string fileName)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (TextReader reader = new StreamReader(fileName, Encoding.UTF8))
        {
            return (T)serializer.Deserialize(reader);
        }
    }
    

    调用它:

    MyType typeInstance = default(MyType).ReadFromXml(path_to_data);
    

    这很可怕,但在某种程度上这是解决问题的一种方式。

    我怀疑我实际上只是把它吸起来然后做:

    MyType typeInstance = GenericXmlSerialisationExtender.ReadFromXml<MyType>(...);
    

    如果你能给GenericXmlSerialisationExtender起一个更响亮的名字,那应该不会太痛苦。

    【讨论】:

    • 谢谢...您能否解释一下为什么编译器不能将其扩展为您实际执行的方式(这是我所期望的)?只是为了我的理解真的......
    • @Matt:您正在尝试添加一种不存在的继承,真的。我敢说该语言可以按照这些思路设计,但它可能会在不同的地方增加额外的复杂性。
    • 乔恩 - 谢谢 - 你能推荐任何好的阅读材料来找出它为什么不能被支持吗?因为据我了解,支持语法所需的所有元素都已经存在......所以我想我一定遗漏了一些东西。
    • @Matt:关于为什么特性没有实现的文档往往不多。 Eric Lippert 喜欢谈论设计、实现和测试功能的成本——也许这种继承还不够引人注目?
    • 乔恩 - 谢谢,我认为这给了我足够好的理解!
    猜你喜欢
    • 2022-07-22
    • 1970-01-01
    • 2010-10-26
    • 2011-05-12
    • 2015-03-28
    • 2011-05-31
    • 2012-04-12
    • 1970-01-01
    相关资源
    最近更新 更多