2011-08-04 2 views
3

나는 사용자가 테스트를 실행할 수있는 응용 프로그램을 작성 중입니다. 테스트는 구성, 온도 및 벤치 마크와 같은 여러 가지 다른 개체로 구성됩니다. 설정 등은 XML간에 앞뒤로 저장됩니다. 다른 환경에서 다른 XML 문서를 다르게 구현할 수 있도록 다른 XElement를 코드에 전달합니다. 나는이 그런 짓을 할 :C#의 정적 메서드에 대한 템플릿

public abstract class BaseClass<T> 
{ 
    abstract static XElement Save(List<T>); 
    abstract static List<T> Load(XElement structure); 
} 

public class Configuration : BaseClass<Configuration> 
{ 
    public string Property1 { get; set; } 
    public string Property2 { get; set; } 
    //etc... 

    public static XElement Save(List<Configuration>) 
    { 
     XElement xRoot = new XElement("Root"); 
     //etc... 
     return xRoot; 
    } 

    public static List<Configuration> Load(XElement structure) 
    { 
     List<BaseClass> list = new List<BaseClass>(); 
     //etc... 
     return list; 
    } 
} 

public class Temperature : BaseClass<Temperature> 
{ 
    public float Value { get; set; } 

    public static XElement Save(List<Temperature>) 
    { 
     //save 
    } 

    public static List<Temperature> Load(XElement structure) 
    { 
     //load 
    } 
} 
[편집]

: 개정 질문 (위 기능의 변경된 서명) [/ 편집]

물론

, 사실의 정적 메소드를 오버라이드 (override) 할 수 없습니다입니다 BaseClass. 이것을 접근하는 가장 좋은 방법은 무엇입니까?

가 가 가 [편집]을 다음,

입니다 [/ 편집]

내가 생각할 수있는 유일한 솔루션 위의 변경 사용 목적 코드가

List<Temperature> mTemps = Temperature.Load(element); 
List<Configuration> mConfigs = Configuration.Load(element); 

Temperature.Save(mTemps); 
Configuration.Save(mConfigs); 
하는 : 나는 다음과 같은만큼 가능한 유효 싶습니다 허용되지 않음 :

+1

왜 메서드가 정적이어야합니까? – BoltClock

+0

Configuration 인스턴스를 만들지 않고 Configuration 목록을 저장하고 싶습니다. 이것이 가능할 수도 있지만 필요한 것은 아닌 것 같습니다. – AGuyInAPlace

답변

3

정적 메서드는 클래스 인스턴스의 일부가 아닙니다. 그래서 그들을 무시하는 것은 어쨌든 말이되지 않습니다. 그들은 구성원이되는 인스턴스의 비 정적 부분에 액세스 할 수 없습니다.

이것은 일종의 전략 패턴 시나리오입니다. 당신은 단지 하나의 static Load를 가질 수 있습니다. & 전달 된 객체의 유형을 검사하는 메소드를 저장하고 그에 따라 행동하십시오. 하지만 제네릭 형식을 사용하여 프로토 타입을 만들고 메서드를 호출하여 각 파생 된 개체 형식 내에서 논리를 유지할 수있게하는 약간 더 영리한 방법이 있습니다.

(편집 다시)

여기 내 원래의 제안과 같은 라인을 따라, 그것은 또 다른 균열입니다. 나는 실제로 이것을 테스트하고 작동하기 때문에, 당신이 찾고있는 모든 기능을 얻기 위해 할 수있는 최선의 방법이라고 생각한다. (유형을 테스트하고 조건에 따라 코드를 호출하는 것 외에는). Load에 대한 유형을 계속 전달해야합니다. 그렇지 않으면 런타임에서 어떤 종류의 리턴이 예상되는지 알 수 없습니다. 그러나 Save은 보편적으로 작동합니다. 그리고 서브 클래스 구현은 강력하게 타입 화된다.

이것은 목록의 첫 번째 객체를 프로토 타입으로 사용하기 만하면됩니다.

public interface IBaseObject 
{ 
    XmlElement Save(IEnumerable<IBaseObject> list); 
    IEnumerable<IBaseObject> Load(XmlElement element); 
} 
public interface IBaseObject<T> where T: IBaseObject 
{ 
    XmlElement Save(IEnumerable<T> list); 
    IEnumerable<T> Load(XmlElement element); 
} 

public class Temperature : IBaseObject<Temperature>, IBaseObject 
{ 

    public XmlElement Save(IEnumerable<Temperature> list) 
    { 
     throw new NotImplementedException("Save in Temperature was called"); 
    } 

    public IEnumerable<Temperature> Load(XmlElement element) 
    { 
     throw new NotImplementedException("Load in Temperature was called"); 
    } 

    // must implement the nongeneric interface explicitly as well 

    XmlElement IBaseObject.Save(IEnumerable<IBaseObject> list) 
    { 
     return Save((IEnumerable<Temperature>)list); 
    } 

    IEnumerable<IBaseObject> IBaseObject.Load(XmlElement element) 
    { 
     return Load(element); 
    } 
} 

// or whatever class you want your static methods living in 

public class BaseObjectFile 
{ 
    public static XmlElement Save(IEnumerable<IBaseObject> list) 
    { 
     IBaseObject obj = list.DefaultIfEmpty(null).First(); // linq 
     return obj==null ? null : obj.Save(list); 
    } 
    public static IEnumerable<IBaseObject> Load<T>(XmlElement element) 
     where T: IBaseObject, new() 
    { 
     IBaseObject proto = new T(); 
     return proto.Load(element); 
    } 
} 

(원본 편집)이 점에서 문제가있다

당신은 유형, 예를 들어,와 정적 메서드를 호출해야합니다

BaseClass<Temperature>.Load() 

저장 방법에는이 방법이 있지만 원하는 부분을 사용할 수 없습니다.Load 메서드는 유일한 매개 변수에 반환 형식에 대한 정보가 없으므로 반환 할 목록 유형을 알 수 없습니다. 따라서 프로토 타입으로 만들 유형을 결정할 수는 없습니다. 그러니까 일반적인 Load 메서드를 사용하려면 위 구문과 같은 형식으로 전달해야합니다.

Save 메서드의 경우 반사를 사용하여 정적 메서드에서 첫 번째 요소의 형식을 가져온 다음 프로토 타입에서 Save 메서드를 호출하여 프로토 타입을 만들 수 있습니다. 따라서 Save 메서드를 원하는 대로만 사용하면되는만큼 많이 사용할 수 있습니다.

는 궁극적으로하지만, 나는 이런 식으로 뭔가를 훨씬 간단하다고 생각 :

public static XElement Save(List<IBaseClass> list) 
{  
    if (list is Temperature) { 
     // do temperature code 
    } else if (list is SomethingElse) { 
     // do something else 
    } 
} 

어쨌든 - 내가 이런 식으로도 저장 방법 일을하기 위해 반사를 요구하는 것 말했듯이. 나는 단순한 접근 방식을 사용하고 싶다.

(원래 나쁜 코드 제거)

+0

또한, 관련이 없지만 밑줄 '_'로 시작하는 메소드 이름에는 어떤 의미가 있습니까? C++, Java 등 다른 언어에서도? 그것은 내가 때때로 보는 것이고 그것이 왜 행해졌는지 궁금합니다. – AGuyInAPlace

+0

이런 식으로'BaseClass.Save (data)'를 할 수 없으므로 구체적인 유형의'data'를 지정해야합니다. 이것은 정확히 OP가 피하려고했던 것입니다. 형식 유추를 사용하여 문제를 해결할 수 있지만 목록을 예를 들어 입력해야합니다. 'List '과 같이 보이지는 않습니다. – svick

+0

내부 사용을위한 방법으로 때때로 사용되는 규칙입니다. 우리에게 실제로이 문제가 있습니다. 당신이 원하는 부분이 실제로 가능하지 않습니다. 저는 대답을 업데이트하려고합니다. –

1

저장 형식에 대해 신경 쓰지 않는다면 내부적으로 리플렉션을 사용하는 직렬화를 자유롭게 사용할 수 있습니다. 당신이 당신의 XML 파일의 큰 부분에 통합하려면

string SerialiseToString<T>(T source) 
{ 
    using (StringWriter sw = new StringWriter() && XmlSerializer xml = new XmlSerializer(typeof(OrderedItem))) 
    { 
     xml.Serializer(sw, source); 
     return sw.ToString(); 
    } 
} 

는 가장 쉬운 방법은이 출력을 구문 분석하고 당신에 추가하는 것입니다. 또는 속성을 직접 반영 할 수도 있습니다.

+0

내가 현재 작업하고있는 BaseClass의 유형에 따라 save() 및 load() 함수에 대한 고유 한 구현을 갖는 것이 두려운 것 같습니다. xml에서 보내거나 파싱해야하는 각 유형에 고유 한 추가 정보가 있습니다. – AGuyInAPlace

1

는 공유 부분이 동일한 경우, 당신은 BaseClass에 넣을 수 있습니다 여기에

public static XElement Save(IEnumerable<BaseClass> list) 
{ 
    var root = new XElement("root"); 
    foreach (var item in list) 
    { 
     item.Save(root); 
    } 
    return root; 
} 

Save(XElement) 가상 방법, 각 유형은 그것을 구현 .

분명히,로드 할 때이 작업을 수행 할 수 없으며, 어떤 유형을로드하는지 알거나 어떤 유형의로드 중인지 알아야합니다.

+0

질문은 객체 목록을 처리하는 메소드에 관한 것입니다. 필자의 가정은 구현마다 각 요소를 저장하는 것보다 목록을 더 많이 수행해야한다는 것입니다. 그렇지 않으면 질문은 사소한 것이고, 우선 정적 인 방법을 처음 사용하는 데는 거의 목적이 없습니다. –

+0

수정. 가장 높은 온도와 최저 온도 또는 벤치 마크 목록 실행 예상 시간과 같은 정보가 목록 전체에서 수집됩니다. 이 정보는 대소 문자를 구별합니다. 즉, 파생 클래스마다 save() 및 load()를 고유하게 구현해야합니다. – AGuyInAPlace

관련 문제