这是滥用“动态”吗?

时间:2011-08-25 07:56:09

标签: c#

以下是使用'动态',在方法IsUnixNewline中,好还是坏?

using System;

class Program
{
    static void Main()
    {
        byte[] bytes = { 32, 32, 32, 10 };
        string text  = "hello\n";

        for (int i = 0; i < bytes.Length; ++i) {
            if (IsUnixNewline(bytes, i)) {
                Console.WriteLine("Found Unix newline in 'bytes'.");
                break;
            }
        }

        for (int i = 0; i < text.Length; ++i) {
            if (IsUnixNewline(text, i)) {
                Console.WriteLine("Found Unix newline in 'text'.");
                break;
            }
        }
    }

    static bool IsUnixNewline(dynamic array, int index)
    {
        return array[index] == '\n' && (index == 0 || array[index - 1] != '\r');
    }
}

5 个答案:

答案 0 :(得分:14)

我会说“是” - dynamic不是必需,并且在运行时它会做什么会增加很多不确定性(当然,抛弃静态编译器)检查);在这种情况下,最好只使用一些重载,IMO:

    static bool IsUnixNewline(char[] array, int index)
    {
        return array[index] == '\n' && (index == 0 || array[index - 1] != '\r');
    }
    static bool IsUnixNewline(byte[] array, int index)
    {
        return array[index] == '\n' && (index == 0 || array[index - 1] != '\r');
    }
    static bool IsUnixNewline(string array, int index)
    {
        return array[index] == '\n' && (index == 0 || array[index - 1] != '\r');
    }

答案 1 :(得分:7)

重写(没有编译器!)以使用char[]代替dynamic。 在将byte[]转换为string时,您需要注意正确的编码,但您应该明白这一点。

using System;

class Program
{
    static void Main()
    {
        byte[] bytes = { 32, 32, 32, 10 };
        string text  = "hello\n";
        char[] characterArray = System.Text.Encoding.ASCII.GetString(bytes).ToCharArray();

        for (int i = 0; i < characterArray.Length; ++i) {
            if (IsUnixNewline(characterArray, i)) {
                Console.WriteLine("Found Unix newline in 'bytes'.");
                break;
            }
        }

        characterArray = text.ToCharArray();
        for (int i = 0; i < characterArray .Length; ++i) {
            if (IsUnixNewline(characterArray, i)) {
                Console.WriteLine("Found Unix newline in 'text'.");
                break;
            }
        }
    }

    static bool IsUnixNewline(char[] array, int index)
    {
        return array[index] == '\n' && (index == 0 || array[index - 1] != '\r');
    }
}

答案 2 :(得分:4)

在我看来不好,就像这个

        var b = IsUnixNewline(new NewObjectNotSupportingIndexer(), 0);

将在开发期间完美地完成编译器,但在运行时会失败。 为什么在没有的时候牺牲类型安全?如果你在开发过程中不知道类型(ComInterop),动态是很有帮助的,但在这种情况下,我认为它造成的伤害比帮助更多。

答案 3 :(得分:1)

dynamic关键字导致运行时类型检查而不是编译时类型检查。我不能为我的生活看到为什么这个简单的操作显然需要运行时类型检查。没有动态,很容易实现同样的目标。我不知道我是否将其归类为滥用动态,我当然将其归类为不必要的。

答案 4 :(得分:0)

首先要认识到byte 不是一个字符是很重要的。因此,要转换那些您需要首先应用编码(即使那只是ASCIIDefault编码)。使用GetString Encoding方法执行此操作将为您提供一个字符串,使两种类型之间的区别为空。

但是,为了更广泛地回答,您应该始终尝试查看类型的共同点。例如,char[]string都实现了IEnumerable<char>。因此,为什么没有使用枚举器检查所有字符的方法,而不是检查每个位置是否为单位换行符?

using System;
using System.Text;
using System.Collections.Generic;

class Program {
    static void Main() {
        byte[] bytes = { 32, 32, 32, 10 };
        string text  = "hello\n";

        if (HasUnixNewline(Encoding.ASCII.GetChars(bytes))) {
            Console.WriteLine("Found Unix newline in 'bytes'.");
        }
        if (HasUnixNewline(text)) {
            Console.WriteLine("Found Unix newline in 'text'.");
        }
   }

    static bool HasUnixNewline(IEnumerable<char> chars) {
        bool prevIsCR = false;
        foreach (char ch in chars) {
            if ((ch == '\n') && (!prevIsCR)) {
                return true;
            }
            prevIsCR = ch == '\r';
        }
        return false;
    }
}

另一种变体是使用所谓的Adapter Pattern,即包装原始实例并提供替代接口的(通常是无状态的)对象。在这种情况下,您可以轻松实现一个只暴露读取索引器并返回字符的接口,然后在IsUnixNewLine方法中使用它。或者,您可以应用相同的模式,以避免在我的示例中使用Encoding类,方法是编写实现IEnumerable<char>并包装IEnumerable<byte>的适配器。