2013-03-20 12 views
5

Mam minimalny interfejs i będę miał do czynienia z kolekcją obiektów, których klasy implementują ten interfejs. Kolekcja (wraz z powiązaną z nią funkcjonalnością) nie przejmuje się żadnymi szczegółami tych obiektów poza ich nazwą, możliwością ich konwersji do formatu XML i możliwością analizowania ich z XML.Wymaganie implementacji interfejsu do statycznej metody analizy składni

Przyszłe implementacje interfejsu znacznie poprawią elementy kolekcji i oczywiście zaimplementują własne metody Parse i ToXml (które będą używane przez kolekcję do odpowiedniego analizowania tych elementów po napotkaniu).

Niestety, nie mogę wyświetlić statycznej metody analizy w interfejsie (przeczytałem thesethreequestions). Nie ma sensu, aby metoda Parse wymagała instancji. Czy jest jakiś sposób, aby wymagać, aby wszystkie implementacje interfejsu miały metodę statycznej analizy parse?

public interface IFoo 
{ 
    string Name { get; } 

    string ToXml(); 

    static IFoo Parse(string xml); // Not allowed - any alternatives? 
} 
+0

Dlaczego chcesz, aby była to statyczna implementacja? Statyczna ma być wspólną metodą pomiędzy różnymi implementacjami (bez zależności od bieżącego obiektu, tylko z innymi statystykami), ale interfejs powinien informować klasę zepsutą, że coś musi zostać zaimplementowane. Myślę, że "statyczny" nie jest tym, czego chcesz tutaj ... – Beachwalker

+0

Każda klasa implementująca ten interfejs będzie musiała analizować instancje z XML, ale każdy będzie analizował bardzo różnie. Sam parsowanie jest unikalne dla konkretnej klasy. – yoozer8

+0

... więc "statyczny" nie jest tym, czego oczekujesz od metody Parse – Beachwalker

Odpowiedz

4

Nie możesz tego zrobić. A statyczne metody i tak nie są polimorficzne, więc nie miałoby to zbytniego sensu.

To, czego chcesz, to jakiś wzór fabryczny.

1

Jedyną alternatywą, która przychodzi mi do głowy jest użycie klasy abstrakcyjnej zamiast interfejsu tutaj. Jednak nie będziesz w stanie przesłonić zachowania metody statycznej w klasach potomnych.

można osiągnąć nieco podobne zachowanie przy użyciu wzorca Factory i wymagające zajęcia wykonawczych IFoo mieć odniesienie do tej fabryki (który może być wstrzykiwany w nich poprzez wstrzyknięcie konstruktora):

public interface IFoo 
{ 
    string Name { get; } 

    string ToXml(); 

    IFooFactory FooFactory { get; } 
} 

public interface IFooFactory 
{ 
    IFoo Parse(string xml); 
} 
+0

Rozważałem to, ale nadpisywanie klas potomnych jest dokładnie tym, czego potrzebujemy. – yoozer8

+0

@Jim, ponieważ nie używasz instancji do wywołania metody statycznej, nie ma sensu jej przesłonić, po prostu napisz ją w każdej klasie, która tego potrzebuje. – wRAR

+0

@ Jim: I to nie działa w przypadku metod statycznych. Nie można przesłonić metody statycznej. –

2

Zakładając Parse pobiera ciąg i zamienia ją w pełni zaludnionych obiektu, jak o metodzie Hydrate zamiast, jak:

interface IFoo { 
    string Name { get; set; } 
    int Age { get; set; } 
    void Hydrate(string xml); 
} 

class Foo : IFoo { 
    public string Name { get; set; } 
    public int Age { get; set; } 

    public void Hydrate(string xml) { 
     var xmlReader = ...etc...; 
     Name = xmlReader.Read(...whatever...); 
     ...etc...; 
     Age = xmlReader.Read(...whatever...); 
    } 
} 

void Main() { 
    IFoo f = new Foo(); 
    f.Hydrate(someXml); 
} 

Or Fluent go trochę:

public IFoo Hydrate(string xml) { 
    // do the same stuff 
    return this; 
} 

void Main() { 
    IFoo f = new Foo().Hydrate(someXml); 
} 
0

Może w ten sposób?

Nawet jeśli powyższe może być rozwiązaniem, zachęcam do skorzystania z fabryki abstact i/lub metody szablonów. Zobacz zamiast tego Template Method Pattern. Inną opcją może być użycie Extension method, jeśli nie chcesz go udostępnić w kilku implementacjach.

0

Najogólniej mówiąc, były znane (przy okazji), aby użyć metody rozszerzenie dla rzeczy tak:

public interface IFoo 
{ 
    string Name {get;} 
    string ToXml();  
} 

public class Foo : IFoo 
{ 
    public Foo(string name) 
    { 
     Name = name; 
    } 
    public string Name {get; private set;} 
    public string ToXml() 
    { 
     return "<derp/>"; 
    } 
} 

więc to instancja rzeczy, niech obsłużyć „statyczny” bit:

public static class FooExts 
{ 
    public static IFoo Parse(this string xml) 
    { 
     return new Foo("derp"); 
    } 
} 

a test:

void Main() 
{ 
    var aFoo = "some xml".Parse(); 
    Console.WriteLine(aFoo.ToXml()); 
} 

Jak wspomina @Jim, nie jest przypadek, w którym nie chcą się Foo plecach, w którym to przypadku można użyć coś takiego:

public static T Parse<T>(
    this string xml, 
    Func<string, IFoo> useMeUseMe = null) 
    where T:IFoo 
{ 
    if(useMeUseMe == null) 
     useMeUseMe = (x => new Foo(x)); 
    return (T)useMeUseMe("derp"); 
} 

niestety, musimy teraz powiedzieć metodę, co chcemy, kiedy odbiega od „normy”:

var aFoo = "some xml".Parse<Foo>(); 
Console.WriteLine(aFoo.ToXml());  
var aBar = "some xml".Parse<Bar>(s => new Bar(s)); 
Console.WriteLine(aBar.ToXml());  
+0

Nie jestem pewien, czy to zadziała; co się dzieje, gdy 'public class Bar: IFoo' musi coś parsować? – yoozer8

+0

@ Jim Zgadzam się, że to nie jest idealne, ale dla przykładu, po prostu nazwałbyś "jakiś ciąg". Pars, tak jak wszyscy inni ... czy nie rozumiem twojego pytania? – JerKimball

+0

Twoja implementacja 'Parse (ten ciąg xml)' zwraca nowe 'Foo'. Nowa klasa musiałaby zwrócić 'Bar'. – yoozer8

1

Wyodrębniłbym wszystkie metody związane z serializacją do innego interfejsu. Rozważmy następujący przykład:

public interface IFoo 
{ 
    string Name { get; } 
    IFooSerializer GetSerializer(string format); 
} 

public enum FooSerializerFormat { Xml, Json }; 

public interface IFooSerializer 
{ 
    string Serialize(IFoo foo); 
    IFoo Deserialize(string xml); 
} 

public class Foo : IFoo 
{ 
    public string Name { get; } 

    public IFooSerializer GetSerializer(FooSerializerFormat format) 
    { 
     case FooSerializerFormat.Xml: 
      return new FooXmlSerializer(); 

     case FooSerializerFormat.Json: 
      return new FooJsonSerializer(); 
    } 
} 

public class FooXmlSerializer : IFooSerializer { /* Code omitted. */ } 
public class FooJsonSerializer : IFooSerializer { /* Code omitted. */ } 
Powiązane problemy