2014-05-22 4 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. 좌표 데이터 (기본 데이터로 PointBase 사용).
  2. ScatterChart (포인트 사용).
  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; 
    } 

따라서 위의 방법은 두 개의 문자열 배열을 수신합니다. 첫 번째 문자는 시리즈의 이름을 나타냅니다 (예 : "Tokyo"및 "London"). 두 번째 것은 차트 범주의 이름을 나타냅니다. 예를 들어 월 이름은 "January", "February"등입니다.

이 메서드는 이름을 사용하는 Dictionary 개체를 만들기로되어 있습니다 각 카테고리 (내 경우 - 매달)에 대한 데이터를 나타내는 객체의 대응하는 배열과 키로서의 세리 (serie). 예를 들어, Dictionary의 단일 키 - 값 쌍은 다음과 같아야합니다. 키 : "London"; 값 : 17, 16, 20, 25 (데이터가 각 달의 최대 온도를 나타냄).

저는 기본적으로 선, 산산조각 또는 거품 형 차트 (CoordinateChart, ScatterChart 및 BubbleChart 클래스로 표시)를 만들 때마다 동일한 알고리즘을 실행합니다. 유일한 차이점은 내가 생성하는 사전의 유형입니다.

  1. CoordinateChart 사전 사용 (문자열을가 PointBase은 [])
  2. scatterchart에가 Dicitonary 사용 (문자열을 가리키고 [])
  3. BubbleChart 사전 (문자열, 거품 [])

I를 사용 '<'및 '>'문자가 '('및 ')'로 바뀌었기 때문에 사라졌습니다.

그래서 내가 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); 

오류 상태의 메시지 '사전 (문자열, T)에 입력 사전 (문자열 된 PointBase)를 변환 할 수 없습니다'. 그들은 내가 무엇을 할 수 :)

사라질 것 때문에

나는, '('및 ')'와 '<'와 '>'문자를 대체?

+0

가 왜 categoriesData 사전을 통해하지 그냥 루프가 .Value가 Point' 또는'사용하여 값을 일치시킬 수'.Value는 거품이다 '당신이 컬렉션을 사용해야 할 때마다? –

답변

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)에서 괜찮습니다. 그러나 CoordinateChart에서 부적절한 ScatterChart가 Dictionary (string, Point)를 반환하기를 원합니다. 그리고 X 속성을 설정하는 것과 같은 방법으로 GetCategoriesData 메서드에서 Point의 Y 속성을 설정하려고합니다. 그래서, 어떻게 이것을 할 수 있습니까? – Yulian

+0

아,이 경우 차트 클래스 자체를 일반 인터페이스 또는 클래스에서 파생시킬 필요가 있습니다. 그런 다음 각 클래스는 재정의 유형을 지정할 수 있습니다. 내 대답을 편집 할 때 잠시만 기다려주세요. – 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 사용을 고려 의미, 당신은 단지 안전 공분산을하자 닷넷.

관련 문제