从开关中的字符串名称返回等效对象
Returning equivalent object from string name in switch
问题的用法有点奇怪。
当我给出对象的字符串名称时,我正在尝试 return 来自函数的 TextBox、Button 甚至 Label 对象之一,如下面的代码:
public [I don't know the type] getObjectClass(string type) {
switch(type) {
case "textbox":
return new TextBox();
break;
case "label":
return new Label();
break;
}
我终于可以访问该对象了:
var obj = getObjectClass("label").Content = "I am new label!..";
首先你需要知道类型的全名。由于要创建 WPF 控件,请将控件类型名称与 'System.Windows.Controls' 连接起来。然后你需要使用 Type.GetType to create an instance of underlying type, and finally use Activator.CreateInstance 创建控件的实例。
public Control CreateControlByTypeName(string typeName) {
string fullName = string.Format("System.Windows.Controls.{0}", typeName);
Type type = Type.GetType(fullName);
return (Control)Activator.CreateInstance(type);
}
您的 return 类型可能需要 dynamic
。
public dynamic getObjectClass(string type)
使用 Control
,Label
和 TextBox
的最低共同祖先,不会让您访问您创建的特定 class 的属性。
请注意,此方法存在风险,因为代码不再是类型安全的。另一种方法是使用泛型,但随后您必须指定类型以及带有类型名称的匹配字符串,这违背了 getObjectClass
方法的目的。
使用动态关键字就可以了
dynamic T;
switch (xnode.Type)
{
case "text":
T = new TextBox();
T.Text = "Enter your name";
Grid.SetColumn(T, 1);
Grid.SetRow(T, row);
break;
}
但我不确定逻辑和开销问题。
简答:找到一些 class 是所有可能 return 类型的超级class。例如,考虑 System.Windows.Controls.Control
。
附加信息:您正在尝试创建一种创建对象的动态方式。这可能很好,例如允许您的用户创建自己的界面,但我觉得这是一种潜在的代码味道。例如,如果你想创建一个文本框然后设置它的文本,你可以这样做:
Control myTextbox = CreateObjectFromTypename("textbox");
((TextBox)myTextbox).Text = "Hello, world!";
但是既然您知道控件将被转换为文本框,为什么需要动态创建它?为什么你不能使用 TextBox myTextbox = new TextBox()
?
同样,我不能肯定地说你的方法不好,但我建议你小心,并确保你确实需要这种动态创作。
因此根据您当前的功能:
public [I don't know the type] getObjectClass(string type) {
类型必须是更通用的类型,例如 Control 或 Object,因为您不知道具体的 return 类型。如果您要 return 多种不同的类型(标签和文本框),则必须 return 它们都继承自的父 class。
这有点棘手
var obj = getObjectClass("label").Content = "I am new label!..";
因为您的基础 class(return 类型)需要关联 Content
属性 才能访问 属性 而无需铸件。最简单的方法(虽然不是我最喜欢的)是施放它 ((Label) getObjectClass("label")).Content
。这不会给你任何编译时间保证,尽管你 returning 的对象实际上有这个 属性。
就我个人而言,我会编写类似于
的方法
public T getObjectClass<T> () where T: new() where T : Control {
return new T();
}
这样您就可以指定您想要的内容 return 并且泛型会自动使其成为正确的类型。当您将它作为字符串传递并让它在 运行 时失败时,您也不会 运行 遇到类似 "lable" 的问题。
我猜您想动态地向 UI 添加控件。
因为你必须在 Control
中设置一个 属性 即对于 TextBox
你必须设置 Text
属性,对于 Label
你有你设置 Content
属性。我建议采用以下方法。
在下面的示例中,我动态地向 UI 添加了一个文本框和标签。
下面代码中的重要部分是Dictionary<Type, Action<Control, String>>
属性。在此 Dictionary
中,我定义了如何根据其 Type
.
为每个 Control
设置内容
注意:
我建议您以这样一种方式进行设计,即不要将实例创建和 属性 分配分成两种不同的方法。一次完成。检查带有签名 getObjectClass(string type, String content, Thickness margin) 的新方法。
XAML:
<Window x:Class="SplashScreenDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="800">
<StackPanel Name="StackPanelObj">
</StackPanel>
</Window>
代码隐藏:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace SplashScreenDemo
{
public partial class MainWindow : Window
{
Dictionary<Type, Action<Control, String>> SetContent = new Dictionary<Type, Action<Control, String>>
{
{ typeof(TextBox), (control, content) => (control as TextBox).Text = content},
{ typeof(Label), (control, content) => (control as Label).Content = content}
};
public MainWindow()
{
InitializeComponent();
Control control = getObjectClass("textbox");
SetContent[control.GetType()](control, "This is a textbox");
Control control2 = getObjectClass("label");
SetContent[control2.GetType()](control2, "This is a label");
StackPanelObj.Children.Add(control);
StackPanelObj.Children.Add(control2);
}
public Control getObjectClass(string type)
{
switch (type)
{
case "textbox":
return new TextBox();
case "label":
return new Label();
default:
return null;
}
}
public Control getObjectClass(string type, String content, Thickness margin)
{
switch (type)
{
case "textbox":
var textBox = new TextBox();
textBox.Text = content;
textBox.Margin = margin;
return textBox;
case "label":
return new Label();
default:
return null;
}
}
}
}
问题的用法有点奇怪。
当我给出对象的字符串名称时,我正在尝试 return 来自函数的 TextBox、Button 甚至 Label 对象之一,如下面的代码:
public [I don't know the type] getObjectClass(string type) {
switch(type) {
case "textbox":
return new TextBox();
break;
case "label":
return new Label();
break;
}
我终于可以访问该对象了:
var obj = getObjectClass("label").Content = "I am new label!..";
首先你需要知道类型的全名。由于要创建 WPF 控件,请将控件类型名称与 'System.Windows.Controls' 连接起来。然后你需要使用 Type.GetType to create an instance of underlying type, and finally use Activator.CreateInstance 创建控件的实例。
public Control CreateControlByTypeName(string typeName) {
string fullName = string.Format("System.Windows.Controls.{0}", typeName);
Type type = Type.GetType(fullName);
return (Control)Activator.CreateInstance(type);
}
您的 return 类型可能需要 dynamic
。
public dynamic getObjectClass(string type)
使用 Control
,Label
和 TextBox
的最低共同祖先,不会让您访问您创建的特定 class 的属性。
请注意,此方法存在风险,因为代码不再是类型安全的。另一种方法是使用泛型,但随后您必须指定类型以及带有类型名称的匹配字符串,这违背了 getObjectClass
方法的目的。
使用动态关键字就可以了
dynamic T;
switch (xnode.Type)
{
case "text":
T = new TextBox();
T.Text = "Enter your name";
Grid.SetColumn(T, 1);
Grid.SetRow(T, row);
break;
}
但我不确定逻辑和开销问题。
简答:找到一些 class 是所有可能 return 类型的超级class。例如,考虑 System.Windows.Controls.Control
。
附加信息:您正在尝试创建一种创建对象的动态方式。这可能很好,例如允许您的用户创建自己的界面,但我觉得这是一种潜在的代码味道。例如,如果你想创建一个文本框然后设置它的文本,你可以这样做:
Control myTextbox = CreateObjectFromTypename("textbox");
((TextBox)myTextbox).Text = "Hello, world!";
但是既然您知道控件将被转换为文本框,为什么需要动态创建它?为什么你不能使用 TextBox myTextbox = new TextBox()
?
同样,我不能肯定地说你的方法不好,但我建议你小心,并确保你确实需要这种动态创作。
因此根据您当前的功能:
public [I don't know the type] getObjectClass(string type) {
类型必须是更通用的类型,例如 Control 或 Object,因为您不知道具体的 return 类型。如果您要 return 多种不同的类型(标签和文本框),则必须 return 它们都继承自的父 class。
这有点棘手
var obj = getObjectClass("label").Content = "I am new label!..";
因为您的基础 class(return 类型)需要关联 Content
属性 才能访问 属性 而无需铸件。最简单的方法(虽然不是我最喜欢的)是施放它 ((Label) getObjectClass("label")).Content
。这不会给你任何编译时间保证,尽管你 returning 的对象实际上有这个 属性。
就我个人而言,我会编写类似于
的方法public T getObjectClass<T> () where T: new() where T : Control {
return new T();
}
这样您就可以指定您想要的内容 return 并且泛型会自动使其成为正确的类型。当您将它作为字符串传递并让它在 运行 时失败时,您也不会 运行 遇到类似 "lable" 的问题。
我猜您想动态地向 UI 添加控件。
因为你必须在 Control
中设置一个 属性 即对于 TextBox
你必须设置 Text
属性,对于 Label
你有你设置 Content
属性。我建议采用以下方法。
在下面的示例中,我动态地向 UI 添加了一个文本框和标签。
下面代码中的重要部分是Dictionary<Type, Action<Control, String>>
属性。在此 Dictionary
中,我定义了如何根据其 Type
.
Control
设置内容
注意: 我建议您以这样一种方式进行设计,即不要将实例创建和 属性 分配分成两种不同的方法。一次完成。检查带有签名 getObjectClass(string type, String content, Thickness margin) 的新方法。
XAML:
<Window x:Class="SplashScreenDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="800">
<StackPanel Name="StackPanelObj">
</StackPanel>
</Window>
代码隐藏:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace SplashScreenDemo
{
public partial class MainWindow : Window
{
Dictionary<Type, Action<Control, String>> SetContent = new Dictionary<Type, Action<Control, String>>
{
{ typeof(TextBox), (control, content) => (control as TextBox).Text = content},
{ typeof(Label), (control, content) => (control as Label).Content = content}
};
public MainWindow()
{
InitializeComponent();
Control control = getObjectClass("textbox");
SetContent[control.GetType()](control, "This is a textbox");
Control control2 = getObjectClass("label");
SetContent[control2.GetType()](control2, "This is a label");
StackPanelObj.Children.Add(control);
StackPanelObj.Children.Add(control2);
}
public Control getObjectClass(string type)
{
switch (type)
{
case "textbox":
return new TextBox();
case "label":
return new Label();
default:
return null;
}
}
public Control getObjectClass(string type, String content, Thickness margin)
{
switch (type)
{
case "textbox":
var textBox = new TextBox();
textBox.Text = content;
textBox.Margin = margin;
return textBox;
case "label":
return new Label();
default:
return null;
}
}
}
}