2014-05-22 31 views
1

我有一些应该生成图表的类。我有三个类为图表系列使用不同类型的数据。我将提供这些类的属性,以避免混淆:)如何使用C#泛型将类的对象转换为类型T的对象?

public class PointBase 
{ 
    public decimal X { get; set; } 
} 

public class Point : PointBase 
{ 
    public decimal Y { get; set; } 
} 

public class Bubble : Point 
{ 
    public decimal Size { get; set; } 
} 

这三个类用作图表系列中的基本数据。一系列图表在其他三个类(图表的一个)中被表示为字典对象。我不会提供图表类的代码,以专注于具体问题。我将只提供这些类的名称:

  1. CoordinateChart(使用PointBase作为基本数据段)。
  2. ScatterChart(使用Point)。
  3. BubbleChart(使用泡泡)。

我有以下的方法,为我所有的图表类做了完全相同的算法。这就是为什么我决定使用泛型的方法。

public Dictionary<string, T[]> GenerateSeriesDataDictionary<T>(string[] series, string[] categories) where T : PointBase, new() 
    { 
     // Create a new Dictionary. 
     Dictionary<string, T[]> seriesData = new Dictionary<string, T[]>(); 

     // Gets the number of categories and assigns the categoriesNumber variable with the returned value. 
     int categoriesNumber = categories.Length; 

     foreach (string serie in series) 
     { 
      Dictionary<string, T> categoriesData = (Dictionary<string, T>)GetCategoriesData(serie); 

      // Create a new array of Ts that will store the data for the current serie. 
      T[] dataArray = new T[categories.Length]; 

      for (int i = 0; i < categoriesNumber; i++) 
      { 
       // If the serie contains a value for the current category, store it in the array. 
       // Otherwise, set the value of the current element of the array to the default one. 
       dataArray[i] = categoriesData.ContainsKey(categories[i]) ? categoriesData[categories[i]] : new T(); 
      } 

      // Add the dataArray to the seriesData Dictionary. 
      seriesData.Add(serie, dataArray); 
     } 

     return seriesData; 
    } 

因此,上述方法接收两个字符串数组。第一个代表该系列的名称,例如“东京”和“伦敦”。第二个代表图表类别的名称 - 例如,月份的名称 - “1月”,“2月”等。

该方法应该创建一个Dictionary对象,该对象使用名称作为一个关键和相应的数组对象,代表每个类别的数据(在我的情况 - 每个月)。例如,Dictionary中的单个键值对应如下所示: 键:“London”;值:17,16,20,25(假设数据代表每个月的最高温度)。

我基本上执行相同的算法,每当我创建一条线,一个分散或气泡图(由CoordinateChart,ScatterChart和BubbleChart类表示)。唯一不同的是我生成的字典的类型。

  1. CoordinateChart使用词典(字符串,PointBase的[])
  2. ScatterChart使用Dicitonary(字符串,点[])
  3. BubbleChart中使用词典(字符串,气泡[])

我用'('和')代替'<'和'>'字符,因为它们似乎消失了:)

这就是为什么我决定把第e逻辑应该在单独的方法中生成Dictionary对象,然后在每个类中重写此方法。

我的方法是这样的:

public virtual Dictionary<string, PointBase> GetCategoriesData(string serie) 
    { 
     Dictionary<string, PointBase> categoriesData = sqlResultDataTable.AsEnumerable() 
      .Where(row => row["City"].ToString() == serie) 
      .Select(row => new KeyValuePair<string, PointBase>(row["Month"].ToString(), new PointBase(decimal.Parse(row["Temperature"].ToString())))) 
      .ToDictionary(item => item.Key, item => item.Value); 

     return categoriesData; 
    } 

这种方法基本上得到所有代表“月”和“温度”值意甲的键值对(例如,“伦敦”)。

所以,我正在做这一切,以便有代码的可重用性。否则,我可以在所有三个类中都做同样的事情,并且我可以在每个类中提供GenerateSeriesDataDictionary方法的单独实现,但我认为这不是一个好方法。

一切都是好的,但我得到一个错误在这条线:

Dictionary<string, T> categoriesData = (Dictionary<string, T>)GetCategoriesData(serie); 

错误状态的消息:“不能型词典(串,PointBase的)转换成词典(串,T)”。

我换成 '(' 和 ')' 的 '<' 和 '>' 字符,因为他们似乎消失了:)

我能做些什么?

+0

为什么你不能仅仅通过categoriesData字典环和匹配使用'价值。价值是Point'或'。价值是泡沫每当你需要使用集合? –

回答

1

使用泛型类型参数创建基类/接口。

public abstract class Chart<T> where T : PointBase, new() 
{ 
    public abstract IDictionary<string, T> GetCategoriesData(string serie); 

    public IDictionary<string, T[]> GenerateSeriesDataDictionary<T>(string[] series, string[] categories) 
    { 
     // Call GetCategoriesData, etc. 
    } 
} 

然后创建派生类与特定的点类型:

public class ScatterChart : Chart<Point> 
{ 
    public override IDictionary<string, Point> GetCategoriesData(string serie) 
    { 
     // Create new Point and set its properties. 
     // We know it is a Point because we specified it in the class generic type. 
    } 

    // ... 
} 

public class BubbleChart : Chart<Point> 
{ 
    public override IDictionary<string, Bubble> GetCategoriesData(string serie) 
    { 
     // Create new Bubble and set its properties. 
     // We know it is a Bubble because we specified it in the class generic type. 
    } 

    // ... 
} 
+0

这对于基类(CoordinateChart)是可以的。但是我希望ScatterChart能够从CoordinateChart中得到字符串(字符串,点)。我想以与设置X属性相同的方式在GetCategoriesData方法中设置Point的Y属性。那么,我怎么能做到这一点? – Yulian

+0

啊,在这种情况下,你需要让Chart类自己派生自一个通用的接口或类。然后每个类都可以指定它的覆盖类型。给我一些时间来编辑我的答案。 – metacubed

+0

@Julian现在检查答案..这是否解决您的问题? – metacubed

0

您不能将Dictionary<string, PointBase>投射到例如Dictionary<string, Bubble>,所以这就是为什么你的代码不会编译。它们不是同一件事。

您或者需要声明categoriesData为Dictionary<string, PointBase>,或者使GetCategoriesData()方法为通用。

0

这是一个类型为variance的问题,协方差更具体。

净让你只能做一个安全的协方差,否则将意味着

Dictionary<string, Bubble> bubbles = GetBubbles(); 
Dictionary<string, PointBase> points = bubbles; 

points["London"] = new Point(); //crash, not a Bubble 

考虑使用IEnumerable即与协变泛型类型的只读接口。

相关问题