2009-06-14 2 views
2

저는 C# 코드 조각에 어려움을 겪었습니다. 문제의 해결책을 찾았지만 이상적인 것은 아닙니다 (아래 DoSomething_WorksButNotIdeal() 참조).C# 캐스팅 및 제네릭

내가 원하는 것은 if, else 문 (어떤 형식을 지원할 것인가에 따라 잠재적으로 방대함) 대신 일반적인 형식을 사용하는 것입니다. 그러나 작동시키지 못합니다. DoSomething_HelpMe() 메서드에서이를 증명하려고했습니다.

어쨌든 이것을 달성 할 수 있습니까? 어떤 도움이라도 대단히 감사합니다.

public interface ITag 
{ 
    string TagName { get; } 
    Type Type { get; } 
    object InMemValue { get; set; } 
    object OnDiscValue { get; set; } 
} 

을하고보다 구체적인하기 위해 ITag<T>를 사용 : 당신이 가질 수 없습니다

public interface ITag 
{ 
    string TagName { get; } 
    Type Type { get; } 
} 

public interface ITag<T> : ITag 
{ 
    T InMemValue { get; set; } 
    T OnDiscValue { get; set; } 
} 


public class Tag<T> : ITag<T> 
{ 
    public Tag(string tagName) 
    { 
     TagName = tagName; 
    } 

    public string TagName { get; private set; } 
    public T InMemValue { get; set; } 
    public T OnDiscValue { get; set; } 
    public Type Type{ get{ return typeof(T);} } 
} 

public class MusicTrack 
{ 
    public MusicTrack() 
    { 
     TrackTitle = new Tag<string>("TrackTitle"); 
     TrackNumber = new Tag<int>("TrackNumber"); 

     Tags = new Dictionary<string, ITag>(); 
     Tags.Add(TrackTitle.TagName, TrackTitle); 
     Tags.Add(TrackNumber.TagName, TrackNumber); 
    } 

    public IDictionary<string,ITag> Tags; 

    public ITag<string> TrackTitle { get; set; } 
    public ITag<int> TrackNumber { get; set; } 
} 


public static class Main 
{ 
    public static void DoSomething_WorksButNotIdeal() 
    { 
     MusicTrack track1 = new MusicTrack(); 
     MusicTrack track2 = new MusicTrack(); 

     // Set some values on the tracks 

     foreach (ITag tag in track1.Tags.Values) 
     { 
      Type type = tag.Type; 

      if (type == typeof(string)) 
      { 
       ((ITag<string>) tag).InMemValue = ((ITag<string>)track2.Tags[tag.TagName]).OnDiscValue; 
      } 
      else if (type == typeof(int)) 
      { 
       ((ITag<int>)tag).InMemValue = ((ITag<int>)track2.Tags[tag.TagName]).OnDiscValue; 
      } 
      else if (type == typeof(bool)) 
      { 
       ((ITag<bool>)tag).InMemValue = ((ITag<bool>)track2.Tags[tag.TagName]).OnDiscValue; 
      } 
      // etc etc 
      else 
      { 
       throw new Exception("Unsupported type."); 
      } 
     } 
    } 

    public static void DoSomething_HelpMe() 
    { 
     MusicTrack track1 = new MusicTrack(); 
     MusicTrack track2 = new MusicTrack(); 

     // Set some values on the tracks 

     foreach (ITag tag in track1.Tags.Values) 
     { 
      Type type = tag.Type; 

      // THIS OBVIOUSLY DOESN'T WORK BUT I'M JUST TRYING TO DEMONSTRATE WHAT 
      // I'D IDEALLY LIKE TO ACHIEVE 
      ((ITag<typeof(type)>)tag).InMemValue = ((ITag<typeof(type)>)track2.Tags[tag.TagName]).OnDiscValue; 
     } 
    } 
} 

답변

4

이유라도?

public interface ITag<T> : ITag 
{ 
    new T InMemValue { get; set; } 
    new T OnDiscValue { get; set; } 
} 

그런 다음 방법은 ITag을 사용할 수 있습니다.

object ITag.InMemValue 
{ 
    get { return InMemValue; } 
    set { InMemValue = (T)value; } 
} 
object ITag.OnDiscValue 
{ 
    get { return OnDiscValue; } 
    set { OnDiscValue = (T)value; } 
} 

또 다른 옵션은 제네릭이 아닌 ITag의 방법이 될 것입니다

(편집) :

void CopyValueFrom(ITag tag); 

(어쩌면 당신은 같은 (INT Tag<T>)가 필요 것 복사되는 대상에 대해 조금 더 구체적 임)

구체적 구현

public void CopyFromTag(ITag tag) { 
    ITag<T> from = tag as ITag<T>; 
    if(from==null) throw new ArgumentException("tag"); 
    this.TheFirstProperty = from.TheSecondProperty; 
} 
+0

마크, 답장을 보내 주셔서 대단히 감사합니다. 두 가지 제안은 가능한 해결책입니다 :-) 문법적으로 나는 Copy 클래스의 메서드를 사용하여 클래스를 지우지 않기 때문에 1 번째 제안을 선호하지만 어떤 것이 더 잘 수행되는지 알고 싶습니다.하나의 다운 캐스트 만 있기 때문에 2 위를 추측합니다. 첫 번째 변수는 값 변수 인 경우 참조 변수와 더 나쁜 상자 및 unbox에 대해 다운 캐스트하고 업 캐스트해야합니다. –

3

당신이 즉 Tag<T> 구현 내부 정보를 가지고있는 유형을 해결하는 것입니다 해결하는 가장 간단한 방법은, 그래서 추가 : (Tag<T>)는 ITag가 실제로 ITag<T> 캐스트 있다고 가정 할 것이다에 제 (단지 추가를 보여주는!) 기존의 유형에 따르는 bool 정말 추악한 때문에 당신이 정말로, 대신 sourceIsMemtargetIsMem에 대한 enum 유형을 사용한다

public interface ITag 
{ 
    void CopyFrom(bool sourceIsMem, ITag sourceTag, bool targetIsMem); 
} 

public class Tag<T> : ITag<T> 
{ 
    public void CopyFrom(bool sourceIsMem, ITag sourceTag, bool targetIsMem) 
    { 
     ITag<T> castSource = sourceTag as ITag<T>; 
     if (castSource == null) 
      throw new ArgumentException(
       "Source tag is of an incompatible type", "sourceTag"); 

     if (targetIsMem) 
      InMemValue = sourceIsMem ? 
       castSource.InMemValue : castSource.OnDiscValue; 
     else 
      OnDiscValue = sourceIsMem ? 
       castSource.InMemValue : castSource.OnDiscValue; 
    } 
} 

주 d는 다음과 같은 내용을 보여주기 때문에 읽기에는 어려움이있다.

는 이제 일상적인 일을 할 것입니다 방법입니다

public static void DoSomething_HelpMe() 
{ 
    MusicTrack track1 = new MusicTrack(); 
    MusicTrack track2 = new MusicTrack(); 

    // Set some values on the tracks 
    foreach (ITag tag in track1.Tags.Values) 
     tag.CopyFrom(false, track2.Tags[tag.TagName], true); 
} 
+0

Ack ... 그리고 나는 그것이 Marc의 편집이 제안한 것임을 발견했습니다. :) ... 나는 더 좋은 대답이 있다고 결정하기 전에 * 전체 * 대답을 정말로 읽어야합니다. – jerryjvl

0

여기 보일러의 상당한 금액이 필요하지만 당신은 당신이 ITag의 기존 정의를 사용하여 원하는 일을 할 수 있도록 한 가지 방법은, ITag<T>입니다 , 및 Tag<T>. TagSetter 클래스는 on 디스크 값의 메모리 값을 ITag<T>에 대한 유형 안전 방식으로 설정합니다.

/// <summary> 
/// Allows a tag of any type to be used to get a result of type TResult 
/// </summary> 
/// <typeparam name="TResult">The result type after using the tag</typeparam> 
public interface ITagUser<TResult> 
{ 
    TResult Use<T>(ITag<T> tag); 
} 

/// <summary> 
/// Allows a tag of any type to be used (with no return value) 
/// </summary> 
public interface ITagUser 
{ 
    void Use<T>(ITag<T> tag); 
} 

/// <summary> 
/// Wraps a tag of some unknown type. Allows tag users (either with or without return values) to use the wrapped list. 
/// </summary> 
public interface IExistsTag 
{ 
    TResult Apply<TResult>(ITagUser<TResult> user); 
    void Apply(ITagUser user); 
} 

/// <summary> 
/// Wraps a tag of type T, hiding the type itself. 
/// </summary> 
/// <typeparam name="T">The type of element contained in the tag</typeparam> 
class ExistsTag<T> : IExistsTag 
{ 

    ITag<T> tag; 

    public ExistsTag(ITag<T> tag) 
    { 
     this.tag = tag; 
    } 

    #region IExistsTag Members 

    public TResult Apply<TResult>(ITagUser<TResult> user) 
    { 
     return user.Use(tag); 
    } 

    public void Apply(ITagUser user) 
    { 
     user.Use(tag); 
    } 

    #endregion 
} 

public interface ITag 
{ 
    string TagName { get; } 
    Type Type { get; } 
} 

public interface ITag<T> : ITag 
{ 
    T InMemValue { get; set; } 
    T OnDiscValue { get; set; } 
} 


public class Tag<T> : ITag<T> 
{ 
    public Tag(string tagName) 
    { 
     TagName = tagName; 
    } 

    public string TagName { get; private set; } 
    public T InMemValue { get; set; } 
    public T OnDiscValue { get; set; } 
    public Type Type { get { return typeof(T); } } 
} 

public class TagSetter : ITagUser 
{ 
    #region ITagUser Members 

    public void Use<T>(ITag<T> tag) 
    { 
     tag.InMemValue = tag.OnDiscValue; 
    } 

    #endregion 
} 

public class TagExtractor : ITagUser<ITag> 
{ 
    #region ITagUser<ITag> Members 

    public ITag Use<T>(ITag<T> tag) 
    { 
     return tag; 
    } 

    #endregion 
} 

public class MusicTrack 
{ 
    public MusicTrack() 
    { 
     TrackTitle = new Tag<string>("TrackTitle"); 
     TrackNumber = new Tag<int>("TrackNumber"); 

     Tags = new Dictionary<string, IExistsTag>(); 
     Tags.Add(TrackTitle.TagName, new ExistsTag<string>(TrackTitle)); 
     Tags.Add(TrackNumber.TagName, new ExistsTag<int>(TrackNumber)); 
    } 

    public IDictionary<string, IExistsTag> Tags; 

    public ITag<string> TrackTitle { get; set; } 
    public ITag<int> TrackNumber { get; set; } 
} 

public static class Main 
{ 
    public static void DoSomething_WorksButNotIdeal() 
    { 
     MusicTrack track1 = new MusicTrack(); 
     MusicTrack track2 = new MusicTrack(); 

     TagSetter setter = new TagSetter(); 
     TagExtractor extractor = new TagExtractor(); 

     // Set some values on the tracks 

     foreach (IExistsTag tag in track1.Tags.Values) 
     { 
      tag.Apply(setter); 

      // do stuff using base interface if necessary 
      ITag itag = tag.Apply(extractor); 

     } 
    } 
}