C#4 动态关键字 - 为什么不使用?

6

阅读了许多针对这个线程的回复后,我发现很多反感它的人都提到了新关键字被滥用的潜在可能性。我的问题是,什么样的滥用?它怎么会被滥用到让人非常反感的程度?这只是关于纯粹主义吗?还是有一个真正的陷阱我没有看到?

7个回答

17
我认为人们对这个特性表达的反感归根结底是“这是一个糟糕的语言特性,因为它会让不良开发者编写不良代码。” 如果你仔细想一下,按照这种逻辑,所有语言特性都是糟糕的。
当我遇到一段由聪明人添加了On Error Resume Next前缀的VB代码块时,我谴责的不是VB。也许我应该这样做。但是在我的经验中,无论如何都决心往保险丝盒里塞一便士的人都会找到方法。即使你把他的口袋掏空了,他也会自己铸造便士。
至于我,我期待着一种更有用的C#和Python之间的互操作方式。我正在编写越来越多实现此目的的代码。 dynamic关键字不能再慢速一点了,因为当前的方法让我感觉像是1950年代苏联学术界的人前往西方参加会议:出国前要处理大量规则和文件,我很确定有人会一直监视我,在那里我获得的大部分东西都会在返回国境时被没收。

16

有些人认为它是一个会被滥用的工具。就像VB中的"Option Strict Off"和"On Error Resume Next"一样,而像C#和Java这样的“纯”语言从未拥有过。

许多人对"var"关键字也有同样的看法,但我并没有看到它被滥用,一旦人们明白了它与VB的"Variant"不同。

它可能会被滥用在那些懒惰的开发者不想对类进行类型检查,只是使用try catch动态调用而不是编写"if blah is Blah ..."的地方。

我个人认为,在像我最近回答的这个问题这样的情况下,它可以被正确地使用。

我认为真正理解它的力量的人是那些深入研究动态.NET语言的人。


3
var被以不同的方式滥用 - 它降低了可读性,而非安全性。 - TraumaPony
1
我同意。我并不是想暗示其他的意思。 - TheSoftwareJedi
7
如果程序员在变量命名上懒散,或者只是懒得仔细查看“= new bar()”右边的类型声明,那么它只会降低可读性。我认为通过消除对象类型在变量左右重复声明的噪音,它提高了可读性。正如Martin Fowler所说:“任何傻瓜都可以编写计算机可以理解的代码。好的程序员编写人类可以理解的代码。”——忍者戴夫 - Dave The Ninja
2
当然,“var”可以提高可读性。我写了数百个文件,其中可能在一个函数中使用StringBuilder,但我不一定想在文件顶部导入“System.Text”。所以现在有了var,我可以这样做:var builder = new System.Text.StringBuilder(); 而不是System.Text.StringBuilder builder = new System.Text.StringBuilder(); - Dave Markle
@DaveMarkle 为什么你不想在文件顶部导入命名空间?在代码中指定命名空间(特别是当一个类型在页面的多个位置使用时)只会给页面增加噪音,这难道不是吗? - lloydphillips
显示剩余2条评论

7

动态编程很糟糕,因为这样的代码会无处不在:

public dynamic Foo(dynamic other) {
  dynamic clone = other.Clone();
  clone.AssignData(this.Data);
  return clone ;
}

替代:

public T Foo<T>(T other) where T: ICloneable, IAssignData{
    T clone = (T)other.Clone();
    clone.AssignData(this.Data);
    return clone;
}

第一个缺点是没有静态类型信息,没有编译时检查,不具备自我文档化,也没有类型推断,因此人们将被迫在调用现场使用动态引用来存储结果,导致更多的类型丢失,而所有这些问题都会不断恶化。

我已经开始担心动态了。


2
你认为什么会鼓励人们不必要地编写动态代码?又有什么可能会阻止他们这样做呢? - Curt Hagenlocher

6

真正的陷阱?文档严重缺失。整个应用程序的架构存在于编写它的人(或人们)的头脑中。至少在强类型语言中,您可以通过其类定义查看对象的功能。而在动态类型语言中,您必须从其使用中推断出含义,最多只能这样做。最糟糕的是,您根本不知道对象是什么。这就像用JavaScript编写所有内容一样。哎呀!


2
公平地说,这已经有些可能了:接口重的 C# 程序可以使得确定给定调用的实际实现成为一种充满猜测和全文搜索的挑战。 - Shog9
1
是的,但接口提供了某些操作上下文。而动态对象则完全没有上下文。动态 q 的另一端是什么?谁知道呢? - Robert C. Barth

2
当人们意识到使用动态类型时无法获得良好的IntelliSense时,他们将从“热衷于使用dynamic”转变为“必要时使用dynamic,并在其他时间使用var”。
使用dynamic的目的包括:与动态语言和平台(如COM/C++和DLR/IronPython/IronRuby)进行互操作性;以及将C#本身变成带有大括号的IronSmalltalk,其中所有东西都实现了IDynamicObject。
每个人都会度过美好的时光。 (除非你需要维护别人编写的代码)。

我在ActionScript中做了一个项目,它既具有动态性又具有静态性,但我要说的是,动态/静态混合并不起作用。 - FlySwat
1
所有人都会从一个例子中得出概括性结论,至少我是这样的。 :) - Curt Hagenlocher
我在QBASIC中完成了一个项目,但那也不应该成为一种语言。但是关于ActionScript和QBASIC的论点与C#并没有任何相关性。 C#在核心上仍然是静态类型的面向对象编程语言,并融合了非常有用的替代功能集。 - yfeldblum

1

这有点像讨论公共摄像头,当然它们可能会被滥用,但是拥有它们也有好处。

如果您不需要它们,那么您可以在自己的编码指南中禁止使用 "dynamic" 关键字。那么问题在哪里呢?我的意思是,如果您想使用 "dynamic" 关键字做一些疯狂的事情,并假装 C# 是 JavaScript 的变异表亲,那就随便你了。只要把这些实验从我的代码库中排除就行了。 ;)


-2
我看不出当前动态调用方法的方式有何缺陷:
要实现它需要三行代码,或者你可以在 System.Object 上添加一个扩展方法来自动完成:
class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();            
        Console.WriteLine(foo.Invoke("Hello","Jonathan"));
    }        
}

static class DynamicDispatchHelper
{
    static public object Invoke(this object ot, string methodName, params object[] args)
    {
        var t = ot.GetType();
        var m = t.GetMethod(methodName);
        return m.Invoke(ot, args);
    }
}

class Foo
{
    public string Hello(string name)
    {
        return ("Hello World, " + name);
    }
}

2
如果“Hello”被重载会怎样?如果有人为长整型传递了一个整型会怎样?性能方面呢?当你深入探究这条路时,你将不得不重写DLR的很大一部分,但仍无法处理Python或COM互操作。 - Curt Hagenlocher
更不用说自然的C#语法用于索引或中缀运算符。 - Curt Hagenlocher
它只支持基于反射的后期绑定。它不适用于基于IDynamicObject的后期绑定,也不适用于基于JSON或XML的对象。 - Jonathan Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接