2015-05-18 3 views
0

У меня возникли проблемы с реализацией свойства в C# в качестве типа конструктора. В основном у меня есть несколько конкретных типов, которые реализуют интерфейс. Я бы хотел выбрать конкретный тип во время разработки.ТипКонвертер с интерфейсами


using System; 
using System.ComponentModel; 
using System.Drawing; 

/// <summary> 
/// implement a summarizable type 
/// </summary> 
public interface ISummarizable 
{ 
    /// <summary> 
    /// Summarize along rows 
    /// </summary> 
    /// <param name="rawdata"></param> 
    /// <returns></returns> 
    double[] Summarize(double[,] rawdata); 
} 

/// <summary> 
/// calculate by mean value 
/// </summary> 
public class MeanSummary : ISummarizable 
{ 
    public double[] Summarize(double[,] rawdata) 
    { 
     double[] result = new double[rawdata.GetLength(0)]; 
     for (int n = 0; n < result.Length; n++) 
     { 
      double value = 0; 
      for (int j = 0; n < rawdata.GetLength(1); j++) 
       value += rawdata[n, j]/rawdata.GetLength(1); 
      result[n] = value; 
     } 
     return result; 
    } 
} 

/// <summary> 
/// Calculate by max value 
/// </summary> 
public class MaxSummary : ISummarizable 
{ 
    public double[] Summarize(double[,] rawdata) 
    { 
     double[] result = new double[rawdata.GetLength(0)]; 
     for (int n = 0; n < result.Length; n++) 
     { 
      double value = double.MinValue;  // guaranteed to change at least once 
      for (int j = 0; n < rawdata.GetLength(1); j++) 
       value = Math.Max(value, rawdata[n, j]); 
      result[n] = value; 
     } 
     return result; 
    } 
} 

/// <summary> 
/// type converter 
/// </summary> 
public class SummaryTypeConverter : System.ComponentModel.TypeListConverter 
{ 
    public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
      return true; 
     return base.CanConvertFrom(context, sourceType); 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     if (destinationType == typeof(string)) 
      return true; 
     return base.CanConvertTo(context, destinationType); 
    } 

    public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
    { 
     if (value is string) 
      return value.ToString(); 
     return base.ConvertFrom(context, culture, value); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType == typeof(string)) 
     { 
      if(value is ISummarizable) 
      { 
       return value.GetType().Name; 
      } 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 


    /// <summary> 
    /// constructor w/ initializer 
    /// </summary> 
    public SummaryTypeConverter() : 
     base(new Type[] { typeof(MeanSummary), typeof(MaxSummary) }) 
    { 
    } 
} 

public class MyControl : System.Windows.Forms.Control 
{ 
    protected ISummarizable _summary = new MaxSummary(); 

    [TypeConverter(typeof(SummaryTypeConverter))] 
    public ISummarizable Summary { get { return _summary; } set { _summary = value; } } 


} 

В окне просмотра свойств я получаю хороший раскрывающихся собственности «Резюме», с двумя моими конкретными типами. Но выбирая один ошибка

Object of type System.String cannot be converted to type Example.ISummarizable 

Я попытался реализации ISummarizable в ConvertFrom и ConvertTo, но безрезультатно, и попытался ее отладки, используя второй экземпляр Visual Studio, но я не могу даже ловушку эта ошибка , Есть предположения?

+1

что вы ожидаете? Вы сообщаете системе, что вы можете преобразовать 'String' в' ISummaraizable', перейдя в базовый регистр (который не знает, как это сделать вообще) – Carsten

ответ

2

В вашей реализации ConvertFrom, в случае, если вы получаете строку, которая имеет смысл (например, «MaxSummary»), вам нужно вернуть экземпляр этого фактического типа вместо вызова базового метода (как сказал Карстен).

Вы можете попытаться сделать это с помощью отражения (найдите тип с этим именем, проверьте, является ли оно ISummarizable, вызовите конструктор) или с помощью оператора switch.

С отражением, ваш код будет:

public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
{ 
    if (value is string) 
    { 
     var source = (string)value; 
     var sourceType = Type.GetType(source); 

     if (sourceType != null && typeof(ISummarizable).IsAssignableFrom(sourceType)) 
     { 
      var constructor = sourceType.GetConstructor(Type.EmptyTypes); 
      var sourceInstance = constructor.Invoke(new object[0]); 

      return sourceInstance; 
     } 
    } 

    return base.ConvertFrom(context, culture, value); 
} 
+0

awesome! С простым добавлением улучшенного «ConvertTo» (см. Редактирование оригинала) он отлично работает! –

Смежные вопросы