2012-03-27 2 views
8

나는 사건이 일어나는 곳인 Venue이라는 개념을 가진 응용 프로그램을 가지고 있습니다. Venue에는 VenuePart이 많이 있습니다. 그래서, 그것은 다음과 같습니다서로 상속하지만 서로 상속하는 속성을 가진 C# 클래스는 어떻게 구성합니까?

public abstract class Venue 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<VenuePart> VenueParts { get; set; } 
} 

Venue는 기울기를 가지고 VenuePart의 특정 종류가 HoleVenuePart라는 VenueGolfCourseVenue 될 수 있습니다 앞으로

public class GolfCourseVenue : Venue 
{ 
    public string Slope { get; set; } 
    public virtual ICollection<HoleVenuePart> Holes { get; set; } 
} 

, Venue에서 상속받은 다른 종류의 Venue도있을 수 있습니다. 그들은 자신의 필드를 추가 할 수 있으며 항상 자신의 특정 유형의 VenuePart을 갖습니다. 여기

VenuePart 클래스입니다 : 정말이 일을 단지를해야 할 때 지금은 GolfCourseVenue이와 컬렉션을 가지고 있기 때문에

public abstract class VenuePart 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public abstract string NameDescriptor { get; } 
} 

public class HoleVenuePart : VenuePart 
{ 
    public override string NameDescriptor { get { return "Hole"; } } 
    public int Yardage { get; set; } 
} 

내 선언은 위, 잘못된 것 같다. 유형이 다르니까 무시할 수는 없습니다. 맞습니까? 보고서를 실행할 때 클래스를 일반적으로 참조하기를 원합니다. 여기서는 VenueVenuePart을 방금 뱉습니다. 그러나 양식 등을 렌더링 할 때 구체적으로 말씀 드리고자합니다.

나는 이와 같은 관계가 많고 내가 뭘 잘못하고 있는지 궁금해하고 있습니다. 예를 들어, OrderItem을 갖는 Order을 가지지 만 특정 종류의 OrderItem을 갖는 특정 종류의 Order도 있습니다.

업데이트 :이 클래스는 Entity Framework Code-First 엔터티입니다. 나는 이것이 중요하지 않길 기대했지만, 아마도 그렇게되었을 것이라고 생각한다. Code-First가 테이블을 제대로 만들 수있는 방법으로 클래스를 구조화해야합니다. Code-First는 제네릭을 처리 할 수있는 것처럼 보이지 않습니다. 죄송이 구현 세부 사항 우아한 솔루션의 방법으로 점점 :/

업데이트 2 : 특정의 수 아형 내에서 목록을 제한 할 수있는 방법이 될 듯 Covariance and Contravariance에서 지적 검색, 연결 사람 하위 유형 자체. 그것은 정말로 유망한 것처럼 보이지만 그 사람은 대답을 삭제했습니다! 누구든지 이러한 개념을 어떻게 활용할 수 있는지에 대한 정보가 있습니까?

업데이트 3 : 사람들을 혼동시키고 문제를 설명하는 데 도움이되지 않았기 때문에 하위 개체에 있던 탐색 속성을 제거했습니다.

다음
public abstract class VenuePart 
{ 
    public abstract string NameDescriptor { get; } 
} 

public class HoleVenuePart : VenuePart 
{ 
    public string NameDescriptor { get{return "I'm a hole venue"; } } 
} 

public class Venue<T> where T : VenuePart 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual ICollection<T> VenueParts { get; set; } 
} 

public class GolfCourseVenue : Venue<HoleVenuePart> 
{ 
} 

GolfCourseVenue이 HoleVenueParts 또는 슈퍼 클래스 HoleVenueParts를 포함 할 수 있습니다 수집 VenueParts을 가지고 :

답변

2

여기에 하나 개의 가능한 옵션을 사용하여 제네릭입니다. Venue의 다른 특수화는 VenueParts가 해당 장소에 특정한 VenueParts를 포함하도록 제한합니다.당신이

public abstract class VenuePart 
{ 
    public abstract string NameDescriptor { get; } 
} 

public class HoleVenuePart : VenuePart 
{ 
    public string NameDescriptor { get{return "I'm a hole venue"; } } 
} 

public class Venue 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual ICollection<VenuePart> VenueParts { get; set; } 
} 

public class GolfCourseVenue : Venue 
{ 
} 

이제 GolfCourseVenue이 VenueParts 또는 슈퍼 클래스 VenueParts를 포함 할 수 있습니다 수집 VenueParts을 가지고 있었다으로

두 번째 가능성

꽤 많이 있습니다. 여기 Venue의 모든 전문화에는 적절한 유형의 VenuePart가 포함될 수 있습니다.

public abstract class VenuePart 
{ 
    public abstract string NameDescriptor { get; } 
} 

public class HoleVenuePart : VenuePart 
{ 
    public override string NameDescriptor { get{return "I'm a hole venue"; } } 
} 

public abstract class Venue 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public abstract ICollection<VenuePart> VenueParts { get; } 
} 

public class GolfCourseVenue : Venue 
{ 
    private ICollection<HoleVenuePart> _holeVenueParts; 

    public GolfCourseVenue(ICollection<HoleVenuePart> parts) 
    { 
     _holeVenueParts = parts; 
    } 

    public override ICollection<VenuePart> VenueParts 
    { 
     get 
     { 
      // Here we need to prevent clients adding 
      // new VenuePart to the VenueParts collection. 
      // They have to use Add(HoleVenuePart part). 
      // Unfortunately only interfaces are covariant not types. 
      return new ReadOnlyCollection<VenuePart>(
        _holeVenueParts.OfType<VenuePart>().ToList()); 
     } 
    } 

    public void Add(HoleVenuePart part) { _holeVenueParts.Add(part); } 
} 
+0

Part 클래스를 추가 했으므로 왜 추상화가 필요한지 알 수있었습니다. 하지만, 당신은 Venue에 대해 옳습니다. 그것은 추상적 일 필요는 없습니다. – Chris

+0

GolfCourseVenue의 생성자에서 [공분산] (http://msdn.microsoft.com/en-us/library/dd799517.aspx)을 사용하여 VenuePart 컬렉션을 HoleVenueParts로 제한 할 수 있습니까? 이 일의 기복에 대해 잘 알고 있습니까? EF가 이것을 처리하지 못하기 때문에 제네릭 솔루션을 사용할 수 없을 것이라고 생각합니다. – Chris

1

당신은 Covariance

public abstract class Venue 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual IEnumerable<VenuePart> VenueParts { get; set; } 
} 

public class GolfCourseVenue : Venue 
{ 
    public string Slope { get; set; } 

    public GolfCourseVenue() 
    { 
     List<HoleVenuePart> HoleVenueParts = new List<HoleVenuePart>(); 
     HoleVenueParts.Add(new HoleVenuePart()); 
     VenueParts = HoleVenueParts; 
    } 
} 

이 HoleVenuePart이 VenuePart

에서 상속됩니다
+0

귀하의 가정은 정확하며 유망 해 보입니다! 나는이 주제들을 읽을 것이다. – Chris

1

내가 기대 가정 사용할 수 있습니다 공분산에 대한 의견에 대한 답변에서

,이 같은 제안 것 다른 사람들의 조언에 따라 달라집니다. 그러나 제 접근 방식은이 경우 제네릭을 사용하는 것입니다. 제네릭을 사용하면 GolfCourseVenue의 "부품"이 강하게 입력됩니다!

... 내가 입력 한대로 다른 모든 사람들도 제네릭을 말하고 있습니다. 당신은 뚱뚱한 뚱뚱한 사람들이 그렇게 빨리 댕을 치는 방식으로하는거야?!

어쨌든, 척 내가 먼저 아직이야 - 경우에 당신이 이름 Parts을 좋아하지 않았다, 그래서

public class VenuePart 
{ 
} 

public class HoleVenuePart : VenuePart 
{ 
} 

public abstract class Venue<T> where T : VenuePart 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual ICollection<T> Parts { get; set; } 
} 

public class GolfCourseVenue : Venue<HoleVenuePart> 
{ 
    public string Slope { get; set; } 
} 

또한, 두번째 옵션으로, 당신은 너무 인터페이스를 사용할 수 있습니다, 당신은 그것을 부를 수 Holes 파생 된 유형은 golfcourse입니다에게 것으로 알려져 때

public class VenuePart 
{ 
} 

public class HoleVenuePart : VenuePart 
{ 
} 

public interface IPartCollection<T> where T : VenuePart 
{ 
    ICollection<T> Parts { get; set; } 
} 

public abstract class Venue<T> : IPartCollection<T> where T : VenuePart 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Company Company { get; set; } 
    public virtual ICollection<T> Parts { get; set; } 
} 

public class GolfCourseVenue : Venue<HoleVenuePart> 
{ 
    public string Slope { get; set; } 
    ICollection<HoleVenuePart> IPartCollection<HoleVenuePart>.Parts { get { return base.Parts; } set { base.Parts = value; }} 

    public virtual ICollection<HoleVenuePart> Holes { get { return base.Parts; } set { base.Parts = value;}} 
} 
+0

다른 사람들이 들어가기 전에 나는 거의 대답을하지 못합니다.)/비슷한 상황 일지라도 답변을 주셔서 감사합니다. 당신을위한 Upvote! – Chris

0

당신은 제거하는 것이 더 의미가있는 것보다 두 컬렉션의 일부 "설정"경우 기본 클래스는 "모든 부품"수집, 파생 클래스가 필터링 한 동안보기를 제공합니다 베이스 cl 이외에 엉덩이 하나.

참고 사항 : GolfVenue의 전문화 과정을 Venue<VenuePart>으로 만들면 Venue<Type1>Venue<Type2>과 같이 작동하지 않을 수 있습니다. 작업하기에 좋은 기본 클래스가 없습니다.

구현의 유연성을 높이기 위해 기본 클래스 대신 인터페이스를 사용하는 것이 좋습니다. 다른 샘플에서 장소 만이 인터페이스를 구현하기 때문에 너무 gnereic 방법으로 처리 할 수 ​​있습니다 :

public interface IVenue 
{ 
    public int Id { get; } 
    public string Name { get; } 
    public virtual IEnumerabe<VenuePart> VenueParts { get; } 
} 

public interface IGolfCourse : IVenue 
{ 
    public virtual IEnumerabe<HoleVenuePart> Holes { get; } 
} 

이제 golfcourse입니다 사용할 수 있습니다

class GolfCourse:Venue<HoleVenuePart>, IGolfCourse { 
    public virtual IEnumerabe<VenuePart> Holes{ get 
    { 
     return VenueParts.OfType<HoleVenuePart>(); 
    } 
    } 
} 
class OtherPlace:Venue<VenuePart>, IVenue {...} 

List<IVenue> = new List<IVenue> { new GolfCourse(), new OtherPlace() }; 

Nothe GolfCourseOtherPlace 공통 부모 클래스를하지 않아도 (객체 제외), 인터페이스가 없으면 상호 교환 할 수 없습니다.

+0

나는 사용중인 경기장 테이블, 그들이 가지고있는 부품의 개수, 사용중인 부품 등을 뱉어내는 보고서를 가지고 있습니다. 그래서 저는 그것들을 총체적으로 언급 할 필요가 있습니다. 파생 된 유형보다 더 나은 방식으로 인터페이스를 사용하는 방법을 확장 할 수 있습니까? – Chris

+0

은 인터페이스 용 비트로 업데이트되었습니다. –

관련 문제