草庐IT

c# - 处理泛型时编译器的无用期望?

coder 2024-03-20 原文

必须翻译泛型类型或方法(任何语言,而不仅仅是 Java)的编译器原则上有两种选择:

Code specialization. The compiler generates a new representation for every instantiation of a generic type or method. For instance, the compiler would generate code for a list of integers and additional, different code for a list of strings, a list of dates, a list of buffers, and so on.

Code sharing. The compiler generates code for only one representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation, performing type checks and type conversions where needed.

Java 使用代码共享 方法。我相信 C# 遵循代码特化方法,所以根据我使用 C# 的说法,下面的所有代码都是合乎逻辑的。

假设这个 Java 代码片段:

public class Test {

    public static void main(String[] args) {
        Test t = new Test();
        String[] newArray = t.toArray(new String[4]);
    }

    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        //5 as static size for the sample...
        return (T[]) Arrays.copyOf(a, 5, a.getClass());
    }
}

代码共享方法将导致此代码发生类型删除后:

public class Test {

    public static void main(String[] args) {
       Test t = new Test();
       //Notice the cast added by the compiler here
       String[] newArray = (String[])t.toArray(new String[4]);
    }

    @SuppressWarnings("unchecked")
    public Object[] toArray(Object[] a) {
       //5 as static size for the sample...
       return Arrays.copyOf(a, 5, a.getClass());
    }
}

所以我的问题是:

精确这个初始类型转换的必要性是什么? :

(T[]) Arrays.copyOf(a, 5, a.getClass());

而不是简单地做(在​​类型删除之前,在编码时):

Arrays.copyOf(a, 5, a.getClass());

编译器真的需要这种类型转换吗?

好的,Arrays.copyOf返回 Object[]并且在没有显式向下转换的情况下不能被更具体的类型直接引用。

但是编译器不能在这种情况下做出努力,因为它处理的是泛型类型(返回类型!)?

确实,编译器对方法的调用行应用显式转换还不够吗? :

(String[])t.toArray(new String[4]);

已更新---------------------------------------- --------------------------

感谢@ruakh 的回答。

这里有一个示例,证明即使在编译时才出现显式强制转换也是相关的:

public static void main(String[] args) {
   Test t = new Test();
   String[] newArray = t.toArray(new String[4]);
}


public <T> T[] toArray(T[] a) {
   return (T[]) Arrays.copyOf(a, 5, Object[].class);
}

转换为 T[]是向用户发出一些警告,表明类型转换可能不相关的唯一方法。事实上,我们最终得到了 Object[] 的沮丧。至 String[] ,这导致了 ClassCastException在运行时。

因此,对于“编译器对方法的调用行应用显式转换还不够”这一点,答案是:

开发人员并不掌握此转换,因为它是在编译步骤自动创建的,因此此运行时功能不会警告用户在启动编译之前深入检查其代码的安全性。

简而言之,这个 Actor 值得出现。

最佳答案

您的推理有两个问题。

一个问题是显式强制转换既是编译时特性(静态类型系统的一部分)又是运行时特性(动态类型系统的一部分)。在编译时,它们将一种静态类型的表达式转换为另一种静态类型的表达式。在运行时,它们通过强制要求动态类型实际上是该静态类型的子类型来确保类型安全。在您的示例中,当然会跳过运行时功能,因为删除意味着没有足够的信息来在运行时强制执行转换。但编译时功能仍然相关。

考虑这个方法:

private void printInt(Number n)
{
    Integer i = (Integer) n;
    System.out.println(i + 10);
}

您认为以下内容是否有效:

Object o = 47;
printInt(o);            // note: no cast to Number

因为 foo 无论如何都会立即将其参数转换为 Integer,因此无需要求调用方将其转换为 Number

您的推理线的另一个问题是,尽管删除和未经检查的强制转换确实会牺牲一点类型安全性,但编译器会通过发出警告来补偿这种牺牲。如果您编写的 Java 程序不提供任何未经检查的(或原始类型的)警告,那么您可以确定它不会因隐式的、仅运行时的原因而抛出任何 ClassCastException ,编译器生成的向下转换。 (我的意思是,当然,除非你要抑制此类警告。)在你的例子中,你有一个方法声称是通用的,并且声称它的返回-type 与其参数类型相同。通过向 T[] 提供显式转换,您让编译器有机会发出警告并告诉您它无法在该位置强制执行该声明。如果没有这样的转换,就没有地方可以警告调用方法中可能产生的 ClassCastException

关于c# - 处理泛型时编译器的无用期望?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13637284/

有关c# - 处理泛型时编译器的无用期望?的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  4. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  7. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  8. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

  9. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  10. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

随机推荐