2009-02-05 4 views
8

Ich fange an, mich in Extension-Methoden zu verlieben, aber ich weiß nur nicht, wie man eine EM nur für einen bestimmten Objekttyp erstellt.Wie kann ich eine gemeinsame Erweiterungsmethode auf mehrere nicht verwandte Typen in einem SDK eines Drittanbieters anwenden?

Ich habe zum Beispiel:

public static void AddPhoneNumberToContact(this Contact contact, PhoneType type, String number) 
{ 
    lock (contact) 
    { 
     PhoneRow pr = PhoneRow.CreateNew(); 
     pr.SetDefaults(); 
     pr.PtypeIdx = type; 
     pr.PhoneNumber = number; 
     contact.Phones.Add(pr); 
     pr = null; 
    } 
} 

Mein Problem ist, dass ich diese Methode in der Person Objekt auch haben will, und das ist, warum ich

AddPhoneNumberToContact 
AddPhoneNumberToPerson 

genannt Gibt es eine Möglichkeit zu haben AddPhoneNumber und beschäftigen sich mit dem Objekt, das zur Verfügung gestellt wird?

oder die Lösung

public static void AddPhoneNumber(this object contact, ... 
{ 
    ... 

    if(typeof(Contact) == contact) 
     ((Contact)contact).Phones.Add(pr); 
    else if(typeof(Person) == contact) 
     ((Person)contact).Phones.Add(pr); 
} 

Danke zu haben.

+0

wie das mit Schlössern Watch out. Wenn der Anrufer von AddPhoneNumberToContact diese Sperre nicht kennt und Contact selbst vor dem Anruf sperrt, haben Sie einen garantierten Deadlock. Normalerweise sperre ich ein privates Objekt. Mit Erweiterungsmethoden ist dies jedoch nicht möglich. – Mendelt

+0

Bitte bearbeiten Sie den Beitrag, um zu verdeutlichen, dass diese Klassen nicht geändert werden können. Und auch die Vererbungshierarchie. –

+0

@Anton Gogolev Es ist genau dort im Titel! "3rd party SDK" – balexandre

Antwort

11

Wie über das Schreiben von zwei Erweiterungsmethoden:

public static void AddPhoneNumber(this Contact contact, PhoneType type); 

und

public static void AddPhoneNumber(this Person person, PhoneType type); 

mir sieht sauberer.

Wenn es einen gemeinsamen Code zwischen den beiden gibt, extrahieren Sie diesen in eine separate Methode.

+1

Wie dumm kann ich manchmal sein !!! :) Danke – balexandre

+0

vergaß alles über mehrere Funktionen mit dem gleichen Namen: '((und ich benutze es sehr! Aber es war eine neue Sache für mich, ExMethods (!)) – balexandre

7

Machen Sie Contact und Person implementieren gemeinsame Schnittstelle - sagen IContactWithPhoneNumbers - und schreiben Sie dann eine Erweiterungsmethode "für diese Schnittstelle".

public interface IContactWithPhoneNumbers {} 
public class Contact : IContactWithPhoneNumbers {} 
public class Person : IContactWithPhoneNumbers {} 
public static void AddPhoneNumber(this IContactWithPhoneNumbers obj) {} 
+0

Kontakt und Person sind geschützt, sie stammen von einem SDK. – balexandre

1

Lesen Sie Ihre Kommentare (Objekte stammen von einem SDK und sind nicht editierbar). Ich würde wahrscheinlich etwas tun:

public class Util 
{ 
    //common util method 
    public static void AddPhoneNumber(object obj, string phoneNumber) 
    { 
     if(obj is Contact) 
      ((Contact)contact).Phones.Add(phoneNumber); 
     else if(obj is Person) 
      ((Person)contact).Phones.Add(phoneNumber); 
    } 

    //extension method for Person 
    public static void AddPhoneNumber(this Person p, string phoneNumber) 
    { 
     AddPhoneNumber((object)p, phoneNumber); 
    } 

    //extension method for Contact 
    public static void AddPhoneNumber(this Contact c, string phoneNumber) 
    { 
     AddPhoneNumber((object)c, phoneNumber); 
    } 
} 

Ich denke, die beste Praxis allerdings, wenn Sie die Kontrolle über die zugrunde liegenden Objekte wären eine gemeinsame Schnittstelle zu implementieren.

0

Sie könnten Ihre Erweiterungsmethode generic, zB machen:

public static void AddPhoneNumberToContact<T>(
    this T contact, 
    PhoneType type, 
    String number 
) 
{ 
    PhoneRow pr = PhoneRow.CreateNew(); 
    pr.SetDefaults(); 
    pr.PtypeIdx = type; 
    pr.PhoneNumber = number; 
    ((T)contact).Phones.Add(pr); 
    pr = null; 
} 

Sie werden nicht in der Lage sein lock zu verwenden, da „‚T‘nicht eine Art Referenz, wie durch die lock-Anweisung erforderlich“, so dass Sie muss möglicherweise einen Wert zurückgeben.

Wenn es beschwert mich über nicht in der Lage ist, um die Telefon Methode auf Typen T zu lösen, könnten Sie:

Pässe in einigen function delegate, den Typ T nehmen würde, kehrt nichts, und führen Sie die Aktion ((T)contact).Phones.Add(pr);.

Oder Sie könnten eine Schnittstelle wie folgt erstellen:

public interface IPhoneable 
{ 
    IList<Phone> Phones(); 
} 

Dann, sobald Sie diese Schnittstelle haben, können Sie die folgenden Code zu Ihrer generischen Erweiterungsmethode hinzufügen:

public static void AddPhoneNumberToContact<T>(
    this T contact, 
    PhoneType type, 
    String number 
) where T : IPhoneable {...} 

Hier T ist immer noch ein generischer Typ, aber jetzt hat Ihre AddPhoneNumberToContact-Methode die Anforderung, dass, egal was T ist, er von der IPhoneable-Schnittstelle erbt, die Sie soeben definiert haben, um die Phones() -Methode zu haben.

Siehe auch C# Extension Method for Generic Collections.

+0

Ich werde das besser betrachten, danke für die Einblick. – balexandre

0

Wenn Sie Person und Kontakt nicht ändern können, können Sie eine Unterklasse von ihnen erstellen und sie die gemeinsame Schnittstelle implementieren lassen.

In der Verlängerung Methode deklarieren Sie die gemeinsame Schnittstelle als Parameter:

using System; 
using System.Collections.Generic; 

public class Program 
{ 
    public static void Main() 
    { 
     var p = new MyPerson(); 
     p.Name = "test"; 
     p.AddPhonenumber("555-2356"); 
     Console.WriteLine(string.Join(", ", p.Phonenumber)); 

     var c = new MyContact(); 
     c.Name = "contact"; 
     c.AddPhonenumber("222-235"); 
     Console.WriteLine(string.Join(", ", c.Phonenumber)); 
    } 
} 


public class Contact 
{ 
    public Contact() { 
     this.Phonenumber = new List<string>(); 
    } 
    public string Name { get; set; } 
    public List<string> Phonenumber { get; set; } 
    public string Foo { get; set; } 
} 
public class Person 
{ 
    public Person() { 
     this.Phonenumber = new List<string>(); 
    } 
    public string Name { get; set; } 
    public List<string> Phonenumber { get; set; } 
    public string Bar { get; set; } 
} 

public class MyContact: Contact, IType { 
} 

public class MyPerson: Person, IType { 
} 


public static class Extensions { 
    public static void AddPhonenumber(this IType type, string number){ 
     type.Phonenumber.Add(number); 
    } 
} 

public interface IType { 
    string Name {get; set; } 
    List<string> Phonenumber {get; set;} 
}