C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

変数の中に入っている文字列で評価させたい

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■90211 / inTopicNo.1)  変数の中に入っている文字列で評価させたい
  
□投稿者/ 猪マン (1回)-(2019/02/18(Mon) 14:11:21)

分類:[.NET 全般] 

var method = "Show";
var aisatu = "こんにちは";
MessageBox + "." + method + "(" + aisatu + ")";

このように変数にメソッド名、プロパティ名をつけて使いたい場合があるのですが、
可能でしょうか?c# 6.0を使ってます。
引用返信 編集キー/
■90212 / inTopicNo.2)  Re[1]: 変数の中に入っている文字列で評価させたい
□投稿者/ PANG2 (261回)-(2019/02/18(Mon) 14:32:45)
2019/02/18(Mon) 14:34:36 編集(投稿者)

リフレクションで MessageBox.Show(string text) メソッドを呼ぶ

System.Reflection.MethodInfo m = typeof(MessageBox).GetMethod("Show", new[] {typeof(string) });
m.Invoke(null, new object[] {"こんにちは" });

引用返信 編集キー/
■90213 / inTopicNo.3)  Re[1]: 変数の中に入っている文字列で評価させたい
□投稿者/ WebSurfer (1768回)-(2019/02/18(Mon) 14:39:56)
No90211 (猪マン さん) に返信

その質問をするに至った背景、そもそも何がしたいのかを書いてもらった方が
質問者さんの課題解決のために早そうな気がしますけど・・・
引用返信 編集キー/
■90215 / inTopicNo.4)  Re[2]: 変数の中に入っている文字列で評価させたい
□投稿者/ 猪マン (1回)-(2019/02/18(Mon) 14:43:21)
PANG2 さん
ありがとうございます。結構面倒なんですね!
もっと簡単にevalみたいにできると思っていました。
参考になりました!多謝
引用返信 編集キー/
■90217 / inTopicNo.5)  Re[2]: 変数の中に入っている文字列で評価させたい
□投稿者/ 猪マン (2回)-(2019/02/18(Mon) 14:57:19)
WebSurfer さん
特に何か問題があったわけではないのですが、変数にメッソド名やプロパティ名を
入れて使いたい場合もあるかもしれないので、知っていれば便利かなと思って質問しました。
調べたのですが、PowerShellではevalを使うとできそうなのですが、C#, VBは調べた限り
わからなかったので今回質問した次第です。ありがとうございます。
引用返信 編集キー/
■90222 / inTopicNo.6)  Re[3]: 変数の中に入っている文字列で評価させたい
□投稿者/ WebSurfer (1769回)-(2019/02/18(Mon) 15:17:15)
No90217 (猪マン さん) に返信

> 特に何か問題があったわけではないのですが、変数にメッソド名やプロパティ名を
> 入れて使いたい場合もあるかもしれないので、知っていれば便利かなと思って質問しました。

デリゲートを使うのが近そうな気がします。今はリンク切れとなって見ることができませんが、Microsoft の
C# のチュートリアルにデリゲートを説明したコードがあって、それが自分の PC に残ってましたので、ご参考
に貼っておきます。

4 つのサンプルを一つにまとめているので、コンパイル・実行するには使わない 3 つをコメントアウトするな
どしないとダメですので注意してください。

やりたいこととは違って役に立たなかったらスミマセン。

using System;
using System.Collections;

// デリゲートのチュートリアル
// C# のデリゲートは、C や C++ の関数ポインタと同じ。
// C や C++ の関数ポインタは静的関数だけを参照できるのに対し、デリゲートでは静的メソッドと
// インスタンスメソッドの両方を参照できる。

namespace Example1
{
    // int 型の引数を一つ持つメソッドへの参照型を MyDelegate と定義
    delegate void MyDelegate(int i);

    // MyDelegate p; で参照型 p を宣言できる。
    // new MyDelegate(Function) でメソッド Function への参照を生成できる。

    class Program
    {
        // TaskADelegate を呼んで、その引数としてメソッド DelegateFunction への参照値を渡す
        public static void Main()
        {
            TakesADelegate(new MyDelegate(DelegateFunction)); // DelegateFunction(21); と同じ
        }

        // ポインタ SomeFunction が指すメソッドを呼んで、それに引数として 21 を渡す
        public static void TakesADelegate(MyDelegate SomeFunction)
        {
            SomeFunction(21);
        }

        public static void DelegateFunction(int i)
        {
            System.Console.WriteLine("Called by delegate with number: {0}.", i);
        }
    }
}


// 例2:デリゲートは静的メソッドとインスタンスメソッドの両方を参照できることの例。
namespace Example2
{
    delegate void MyDelegate(); // 引数を持たないメソッドへの参照型を MyDelegate と定義

    public class MyClass
    {
        public void InstanceMethod()
        {
            Console.WriteLine("A message from the instance method.");
        }

        static public void StaticMethod()
        {
            Console.WriteLine("A message from the static method.");
        }
    }

    public class MainClass
    {
        static public void Main()
        {
            MyClass p = new MyClass();

            MyDelegate d = new MyDelegate(p.InstanceMethod);
            d();    // d はインスタンスメソッド p.InstanceMethos() への参照値を持つ。
                    // d() はメソッドそのもの

            d = new MyDelegate(MyClass.StaticMethod);   // 静的なので p.StaticMethod は不可
            d();    // 静的メソッド MyClass.StaticMethod() を呼ぶ
        }
    }
}

// 例3:デリゲートの宣言方法、インスタンス化方法、および呼び出し方法を示す。
// デリゲートを使用すると、書店データベースとクライアントコードの機能の分担を適切に行うこと
// ができる。BookTextClient コードは、書籍の在庫状況や Booksore コードがペーパーバックを検
// 索する方法については関知しない。Bookstore コードは、ペーパーバックの検索後の処理について
// は関知しない。
namespace Bookstore
{
    public struct Book
    {
        public string Title;        // Title of the book.
        public string Author;       // Author of the book.
        public decimal Price;       // Price of the book.
        public bool Paperback;      // Is it paperback?

        public Book(string title, string author, decimal price, bool paperBack)
        {
            Title = title;
            Author = author;
            Price = price;
            Paperback = paperBack;
        }
    }

    // Book 型の引数を一つ持つメソッドへの参照型を ProcessBookDelegate と定義
    public delegate void ProcessBookDelegate(Book book);

    public class BookDB
    {
        ArrayList list = new ArrayList();  // データベース中のすべての本のリスト

        // データベースに本を追加
        public void AddBook(string title, string author, decimal price, bool paperBack)
        {
            list.Add(new Book(title, author, price, paperBack));
        }

        // データベース BookDB のリスト list にあるすべての本について、
        // 本がペーパーバックなら引数 processBook が指す関数を呼ぶ
        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
        {
            foreach (Book b in list)
            {
                if (b.Paperback)
                    processBook(b);
            }
        }
    }
}

namespace BookTestClient
{
    using Bookstore;

    // 本の数量と価格合計および平均を求めるためのクラス
    class PriceTotaller
    {
        int countBooks = 0;
        decimal priceBooks = 0.0m;

        internal void AddBookToTotal(Book book)
        {
            countBooks += 1;
            priceBooks += book.Price;
        }

        internal decimal AveragePrice()
        {
            return priceBooks / countBooks;
        }
    }

    class Test
    {
        static void PrintTitle(Book b)
        {
            Console.WriteLine("   {0}", b.Title);
        }

        static void Main()
        {
            // Book の配列からなる本のデータベースを作る。bookDB はデータベースを指す
            BookDB bookDB = new BookDB();
            AddBooks(bookDB);

            Console.WriteLine("Paperback Book Titles:");

            // メソッド ProcessPaperbackBooks に処置方法 PrintTitle を渡し bookDB を操作する
            // (即ち、データベースの本がペーバーバックなら PrintTile する)
            bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));

            // メソッド ProcessPaperbackBooks に処置方法 AddBookToTotal を渡し bookDB を操作する
            // (即ち、データベースの本がペーバーバックなら数を数えて価格を合計に加える)
            PriceTotaller totaller = new PriceTotaller();
            bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal));
            Console.WriteLine("Average Paperback Book Price: ${0:#.##}", totaller.AveragePrice());
        }

        // テスト用データベースを作るためのメソッド
        static void AddBooks(BookDB bookDB)
        {
            bookDB.AddBook("The C Programming Language",
               "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
            bookDB.AddBook("The Unicode Standard 2.0",
               "The Unicode Consortium", 39.95m, true);
            bookDB.AddBook("The MS-DOS Encyclopedia",
               "Ray Duncan", 129.95m, false);
            bookDB.AddBook("Dogbert's Clues for the Clueless",
               "Scott Adams", 12.00m, true);
        }
    }
}

// 例4:デリゲートの結合方法を示す。
// デリゲートオブジェクトは "+" 演算子を使用して結合できる。結合されたデリゲートは、結合元の複数
// のデリゲートを呼び出す。結合できるのは同じ型のデリゲートだけである。結合されたデリゲートを "-" 
// 演算子を使用して取り除くこともできる。
namespace Example4
{
    delegate void MyDelegate(string s);

    class MyClass
    {
        public static void Hello(string s)
        {
            Console.WriteLine("  Hello, {0}!", s);
        }

        public static void Goodbye(string s)
        {
            Console.WriteLine("  Goodbye, {0}!", s);
        }

        public static void Main()
        {
            MyDelegate a, b, c, d;  // デリゲートの宣言

            // a にメソッド Hello への参照値を代入
            a = new MyDelegate(Hello);
            // b にメソッド Goodbye への参照値を代入
            b = new MyDelegate(Goodbye);
            // a と b を結合して c に代入 
            c = a + b;
            // c から a を取り除いて d に代入
            d = c - a;

            Console.WriteLine("Invoking delegate a:");
            a("A");
            Console.WriteLine("Invoking delegate b:");
            b("B");
            Console.WriteLine("Invoking delegate c:");
            c("C");
            Console.WriteLine("Invoking delegate d:");
            d("D");
        }
    }
}

引用返信 編集キー/
■90223 / inTopicNo.7)  Re[3]: 変数の中に入っている文字列で評価させたい
□投稿者/ PANG2 (262回)-(2019/02/18(Mon) 15:34:56)
2019/02/18(Mon) 15:36:31 編集(投稿者)
No90215 ( 猪マン さん) に返信
> もっと簡単にevalみたいにできると思っていました。

動的コンパイルで

private void Button_Click(object sender, EventArgs e)
{
	string s = @"System.Windows.Forms.MessageBox.Show(""こんにちは"");";
	MyEval(s);
}

public static object MyEval(string text)
{
	string cs = @"public class foo {public static void Main() {" + text + "}}";

	CSharpCodeProvider cscp = new CSharpCodeProvider();
	ICodeCompiler cc = cscp.CreateCompiler();
	CompilerParameters param = new CompilerParameters();
	param.GenerateInMemory = true;
	param.ReferencedAssemblies.Add("System.Windows.Forms.dll");
	CompilerResults cr = cc.CompileAssemblyFromSource(param, cs);
	Assembly asm = cr.CompiledAssembly;
	Type type = asm.GetType("foo");
	MethodInfo mi = type.GetMethod("Main");
	return mi.Invoke(null, null);	
}

参考
https://www.atmarkit.co.jp/fdotnet/dotnettips/101compileinvoke/compileinvoke.html

引用返信 編集キー/
■90235 / inTopicNo.8)  Re[3]: 変数の中に入っている文字列で評価させたい
□投稿者/ 魔界の仮面弁士 (2065回)-(2019/02/18(Mon) 18:12:28)
No90215 ( 猪マン さん) に返信
> もっと簡単にevalみたいにできると思っていました。

CSharpScript クラスの EvaluateAsync メソッドという手も。


// Install-Package Microsoft.CodeAnalysis.CSharp.Scripting
//
using System;
using System.Windows.Forms;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.CSharp.Scripting;

static class Program
{
 [STAThread]
 public static void Main()
 {
  string script = "MessageBox.Show( \"こんにちは\", \"テスト\", MessageBoxButtons.OKCancel, MessageBoxIcon.Question )";

  var refOpt = ScriptOptions.Default
   .WithReferences(typeof(MessageBox).Assembly)
   .WithImports("System.Windows.Forms");

  DialogResult result = CSharpScript.EvaluateAsync<DialogResult>(script, refOpt).GetAwaiter().GetResult();

  Console.WriteLine(result.ToString());
  Console.ReadLine();
 }
}
引用返信 編集キー/
■90238 / inTopicNo.9)  Re[4]: 変数の中に入っている文字列で評価させたい
□投稿者/ 猪マン (3回)-(2019/02/19(Tue) 09:41:46)
いろいろな解決方法があるんですねぇ。勉強になりました。ありがとうございます〜。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ