2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

csc は嘘つき あるものを無いと主張してきやがる

Posted at

csc は嘘つき

csc は、最近の Windows に標準搭載されている C# のコンパイラである。
実行ファイルは

C:\Windows\Microsoft.NET\Framework\v4.0.30319

などにあるので、事前にパスを通しておく。

例として、適当なライブラリを書く。

TestLib.cs
public class TestLib
{
	static int Func(int x)
	{
		return x + 30;
	}
}

Funcpublic がついていないのはわざとである。

このライブラリをコンパイルする。

csc /target:library /optimize+ TestLib.cs

このライブラリを使うためのコードを書く。

Test.cs
class Test
{
	public static void Main()
	{
		System.Console.WriteLine(TestLib.Func(42));
	}
}

コンパイルを試みる。

csc /optimize+ /reference:TestLib.dll Test.cs

すると、以下のメッセージが出力された。

Microsoft (R) Visual C# Compiler version 4.8.9232.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240

Test.cs(5,36): error CS0117: 'TestLib' に 'Func' の定義がありません。

TestLib に確かに Func の定義を書いているはずなのに、「'TestLib' に 'Func' の定義がありません」と主張してきている。
これは明らかに嘘である。
ILSpy でコンパイルしたライブラリの中身を確認すると、確かに Func の定義が含まれていることがわかる。

ILSpy によるライブラリの内容の確認

C# フィールドやprivateメソッドを無理やり使用する #reflection - Qiita
を参考に、Func を呼び出すコードを書く。

Test2.cs
using System;
using System.Reflection;

class Test2
{
	public static void Main()
	{
		Type libType = Type.GetType("TestLib,TestLib");
		if (libType == null) {
			Console.WriteLine("libType is null");
			return;
		}
		MethodInfo method = libType.GetMethod(
			"Func",
			BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic
		);
		if (method == null) {
			Console.WriteLine("method is null");
			return;
		}
		Console.WriteLine(method.Invoke(null, new object[]{ 42 }));
	}
}

コンパイルする。

csc /optimize+ Test2.cs

すると、コンパイルが通り、実行すると期待した通り 72 が出力された。

まず、Type.GetType(string) で、ライブラリのクラスの型を取得する。
引数は クラス名,ファイル(アセンブリ)名 の形式で指定するとよいようである。

続いて、Type.GetMethod(String, BindingFlags) で、呼び出すメソッドを取得する。
今回は静的メソッドを呼び出すので、それに合わせて BindingFlags を設定する。

最後に、MethodInfo.Invoke(Object, Object[]) で、メソッドを呼び出す。
今回は静的メソッドを呼び出すので、インスタンスを指定する第1引数は適当でよい (無視される)。

このように、実際に存在し、呼び出すことも可能なメソッドについて「ありません」と主張してくる csc は嘘つきである。

javac は正直

同じことを Java で試してみる。
コンパイラのバージョンは javac 21.0.1 である。

Java では、jar に分けるだけではメソッドが使えてしまったので、ライブラリのクラスをパッケージに入れる。

testlib/TestLib.java
package testlib;

public class TestLib {
	static int func(int x) {
		return x + 30;
	}
}

コンパイルして jar にする。

javac testlib\TestLib.java
jar -cf TestLib.jar testlib\TestLib.class

(.class を直接参照しないように) 別のディレクトリで、ライブラリを使うためのコードを書く。

Test.java
public class Test {
	public static void main(String[] args) {
		System.out.println(testlib.TestLib.func(42));
	}
}

コンパイルを試みる。

javac -cp testlib_java\TestLib.jar Test.java

すると、以下のメッセージが出力された。

Test.java:3: エラー: TestLibのfunc(int)はpublicではありません。パッケージ外からはアクセスできません
                System.out.println(testlib.TestLib.func(42));
                                                  ^
エラー1個

「ありません」という嘘をついてきた csc と違って、(今回用いたバージョンの) javac は正直に「アクセスできません」と伝えてきた。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?