С BinaryFormatter
вам не нужно , чтобы узнать тип; метаданные включены в поток (делая его больше, но эй!). Однако вы не можете кастовать , если не знаете тип. Часто в этом сценарии вы должны использовать общеизвестные интерфейсы (неуниверсальные IList
и т. Д.) И рефлексию. И многое из этого.
Я также не могу представить огромное требование знать тип для отображения в PropertyGrid
- так как он принимает object
, просто дайте ему то, что обеспечивает BinaryFormatter
. Есть ли конкретная проблема, которую вы видите там? Опять же, вы можете захотеть проверить IList
(не универсальный) - но не стоит беспокоиться о IList<T>
, так как это не то, что PropertyGrid
проверяет!
Вы, конечно, можете найти T
, если вы хотите (, например, ) - и использовать MakeGenericType()
и Activator.CreateInstance
- не красиво.
OK; вот способ использования пользовательских дескрипторов, который не предполагает знание что-нибудь об объекте или типе списка; если вы действительно хотите, можно расширить элементы списка непосредственно в свойствах, поэтому в этом примере вы увидите 2 поддельных свойства ("Fred" и "Wilma") - это дополнительная работа, хотя ; р
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public override string ToString() {
return Name;
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Person fred = new Person();
fred.Name = "Fred";
fred.DateOfBirth = DateTime.Today.AddYears(-23);
Person wilma = new Person();
wilma.Name = "Wilma";
wilma.DateOfBirth = DateTime.Today.AddYears(-20);
ShowUnknownObject(fred, "Single object");
List<Person> list = new List<Person>();
list.Add(fred);
list.Add(wilma);
ShowUnknownObject(list, "List");
}
static void ShowUnknownObject(object obj, string caption)
{
using(Form form = new Form())
using (PropertyGrid grid = new PropertyGrid())
{
form.Text = caption;
grid.Dock = DockStyle.Fill;
form.Controls.Add(grid);
grid.SelectedObject = ListWrapper.Wrap(obj);
Application.Run(form);
}
}
}
[TypeConverter(typeof(ListWrapperConverter))]
public class ListWrapper
{
public static object Wrap(object obj)
{
IListSource ls = obj as IListSource;
if (ls != null) obj = ls.GetList(); // list expansions
IList list = obj as IList;
return list == null ? obj : new ListWrapper(list);
}
private readonly IList list;
private ListWrapper(IList list)
{
if (list == null) throw new ArgumentNullException("list");
this.list = list;
}
internal class ListWrapperConverter : TypeConverter
{
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(
ITypeDescriptorContext context, object value, Attribute[] attributes) {
return new PropertyDescriptorCollection(
new PropertyDescriptor[] { new ListWrapperDescriptor(value as ListWrapper) });
}
}
internal class ListWrapperDescriptor : PropertyDescriptor {
private readonly ListWrapper wrapper;
internal ListWrapperDescriptor(ListWrapper wrapper) : base("Wrapper", null)
{
if (wrapper == null) throw new ArgumentNullException("wrapper");
this.wrapper = wrapper;
}
public override bool ShouldSerializeValue(object component) { return false; }
public override void ResetValue(object component) {
throw new NotSupportedException();
}
public override bool CanResetValue(object component) { return false; }
public override bool IsReadOnly {get {return true;}}
public override void SetValue(object component, object value) {
throw new NotSupportedException();
}
public override object GetValue(object component) {
return ((ListWrapper)component).list;
}
public override Type ComponentType {
get { return typeof(ListWrapper); }
}
public override Type PropertyType {
get { return wrapper.list.GetType(); }
}
public override string DisplayName {
get {
IList list = wrapper.list;
if (list.Count == 0) return "Empty list";
return "List of " + list.Count
+ " " + list[0].GetType().Name;
}
}
}
}