我希望有一个属性网格,当它有两个SteppedValue对象时会看起来像这样:
但我也希望SteppedValue对象是通用的,例如:
var fastEma = new SteppedValue<int>();
var slowEma = new SteppedValue<float>();
我主要通过实现ExpandableObjectConverter来实现...但我遇到的唯一问题是当我在ConvertFrom中实例化要返回的对象时......我无法想象如何获取T的System.Type(来自此时的通用实例。
问题代码
public override object ConvertFrom(ITypeDescriptorContext iTypeDescriptorContext, CultureInfo cultureInfo, object value)
{
if (value is string)
{
var classType = typeof(SteppedValue<>);
Type[] typeArgs = { typeof(int) }; // <== Need to determine this
// needs to be T of the generic
// instance (not "typeof(int)")
var instanceType = classType.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(instanceType, value);
return o;
}
return base.ConvertFrom(iTypeDescriptorContext, cultureInfo, value);
}
完整代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Test
{
[TypeConverter(typeof(SteppedValueConverter))]
public class SteppedValue<T>
{
public T Begin { get; set; }
public T End { get; set; }
public T Step { get; set; }
public SteppedValue(T begin, T end, T step)
{
Begin = begin;
End = end;
Step = step;
}
public SteppedValue(string str)
{
var parts = ParseParts(str);
Begin = parts[0];
End = parts[1];
Step = parts[2];
}
public static T ToT(object obj)
{
return (T)Convert.ChangeType(obj, typeof(T));
}
public static SteppedValue<T> Parse(string str)
{
return new SteppedValue<T>(str);
}
public List<T> ParseParts(string str)
{
while (str.Contains(" ")) str = str.Replace(" ", " ");
var arr = str.Trim().Split(' ');
if (arr.Length == 0)
return new List<T> { default(T), default(T), default(T) };
else if (arr.Length == 1)
return new List<T> { ToT(arr[0]), ToT(arr[0]), default(T) };
else if (arr.Length == 3 && arr[1].ToLower() == "to")
return new List<T> { ToT(arr[0]), ToT(arr[2]), default(T) };
else if (arr.Length == 5 && arr[1].ToLower() == "to" && arr[3].ToLower() == "step")
return new List<T> { ToT(arr[0]), ToT(arr[2]), ToT(arr[4]) };
throw new Exception("Unable to parse'" + str + "'");
}
public override string ToString()
{
if (Begin.Equals(End))
return Begin.ToString();
else if (Step == null || Step.ToString() == "")
return Begin + " to " + End;
else
return Begin + " to " + End + " step " + Step;
}
}
public class SteppedValueConverter : ExpandableObjectConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext iTypeDescriptorContext, Type type)
{
if (type == typeof(string))
return true;
return base.CanConvertFrom(iTypeDescriptorContext, type);
}
public override object ConvertFrom(ITypeDescriptorContext iTypeDescriptorContext, CultureInfo cultureInfo, object value)
{
if (value is string)
{
var classType = typeof(SteppedValue<>);
Type[] typeArgs = { typeof(int) }; // <== Need to determine this
var instanceType = classType.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(instanceType, value);
return o;
}
return base.ConvertFrom(iTypeDescriptorContext, cultureInfo, value);
}
public override object ConvertTo(ITypeDescriptorContext iTypeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType)
{
if (destinationType == typeof(string) && value.GetType().GetGenericTypeDefinition() == typeof(SteppedValue<>))
return value.ToString();
return base.ConvertTo(iTypeDescriptorContext, cultureInfo, value, destinationType);
}
}
}
答案 0 :(得分:2)
你可以从上下文中获取类型,就像这样(在SteppedValue的情况下,它是第一个泛型类型):
Type steppedValueType = iTypeDescriptorContext.PropertyDescriptor.PropertyType.GetGenericArguments()[0];