gpt4 book ai didi

c# - 我应该如何实例化一个未知类型的类?

转载 作者:太空宇宙 更新时间:2023-11-03 23:13:50 24 4
gpt4 key购买 nike

我有一个 UserControl,它被设计用来编辑一些任意 POCO 的集合。 POCO 是在设计时选择的,因此我可以传递 POCO 中需要显示和编辑的属性的描述,但我正在努力寻找在控件中实例化新 POCO 以添加到集合中的最佳方法。

目前,我正在向包含 IPocoFactory 的控件添加一个新属性,但这似乎并不令人满意,原因如下:

  • 控件用户必须做相当多的工作来创建一个实现 IPocoFactory 接口(interface)的类才能使用控件,否则会非常简单
  • 诸如 DataGrid 之类的控件已经解决了这个问题(尽管我似乎无法弄清楚如何解决问题,尽管我使用 ILSpy 摸索了一段时间!)

谁能为这个问题提出一个合适的模式?我不可能是唯一一个面对它的人!

我想到反射可能在解决方案中发挥作用,但我对此也不太确定:我可以检查 ItemsSource(一个非通用的 IEnumerable) 看看里面有什么,但如果它是空的,就没有什么可看的。

最佳答案

您可以通过调用 ItemsSource.GetType().GetInterfaces() 来获取要创建的类型, 找到 Type IEnumerable<T> 的对象接口(interface)(任何通用集合都将实现),并调用 GetGenericArguments() 在上面。 IEnumerable<T>当然,只有一个类型参数,所以这就是您需要创建其实例的类型。

然后 you can create an instance fairly easily (请参阅下面的更新,了解将这一切包装到单个方法调用中的静态方法):

ObjectType instance = (ObjectType)Activator.CreateInstance("AssemblyName",
"MyNamespace.ObjectType");

您需要声明类型的程序集,but that's a property of Type . Assemblya CreateInstance method以及。这是做同样事情的另一种方法:

Type otype = typeof(ObjectType);
ObjectType instance = (ObjectType)otype.Assembly.CreateInstance(otype.FullName);

如果要实例化的类型没有默认构造函数,这会变得更难看。您必须编写明确的代码来提供值,而且没有办法保证它们有意义。但至少这比给消费者带来的负担要轻得多 IPOCOFactory实现。

顺便记住System.String没有默认构造函数。用 List<String> 测试下面的代码是很自然的,但这会失败。

一旦你有了 ItemsSource 中的对象类型,您可以通过以编程方式枚举属性的名称和类型以及自动生成列来进一步简化维护。如果需要,您可以写一个 Attribute类来控制显示哪些,提供显示名称等。

更新

这是一个粗略的实现,它可以让我创建在不同程序集中声明的类的实例:

/// <summary>
/// Collection item type must have default constructor
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static Object CreateInstanceOfCollectionItem(IEnumerable items)
{
try
{
var itemType = items.GetType()
.GetInterfaces()
.FirstOrDefault(t => t.Name == "IEnumerable`1")
?.GetGenericArguments()
.First();

// If it's not generic, we may be able to retrieve an item and get its type.
// System.Windows.Controls.DataGrid will auto-generate columns for items in
// a non-generic collection, based on the properties of the first object in
// the collection (I tried it).
if (itemType == null)
{
itemType = items.Cast<Object>().FirstOrDefault()?.GetType();
}

// If that failed, we can't do anything.
if (itemType == null)
{
return null;
}

return itemType.Assembly.CreateInstance(itemType.FullName);
}
catch (Exception ex)
{
return null;
}
}

public static TestCreate()
{
var e = Enumerable.Empty<Foo.Bar<Foo.Baz>>();

var result = CreateInstanceOfCollectionItem(e);
}

你可以制作CreateInstanceOfCollectionItem() IEnumerable 上的扩展方法如果你喜欢:

var newItem = ItemsSource?.CreateInstanceOfCollectionItem();

注意

这取决于实际集合是否为通用集合,但它不关心您对集合的引用 类型。 ItemsControl.ItemsSource类型为 System.Collections.IEnumerable ,因为任何标准泛型集合都支持该接口(interface),因此可以转换为它。但是调用GetType()在该非通用接口(interface)引用上将返回引用另一端(可以这么说)对象的实际运行时类型:

var ienumref = (new List<String>()) as System.Collections.IEnumerable;
// fullName will be "System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
// ...or something like it, for whatever version of .NET is on the host.
var fullName = ienumref.GetType().Name;

关于c# - 我应该如何实例化一个未知类型的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37974483/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com