Как я могу применить общий метод расширения к нескольким несвязанным типам в стороннем SDK? - PullRequest
8 голосов
/ 05 февраля 2009

Я начинаю влюбляться в методы расширения, но я просто не знаю, как создать EM только для определенного типа объекта.

у меня например:

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;
    }
}

Моя проблема в том, что я хочу также иметь этот метод в объекте Person, и поэтому я назвал

AddPhoneNumberToContact
AddPhoneNumberToPerson

Есть ли способ иметь AddPhoneNumber и иметь дело с предоставленным объектом?

или решение должно иметь

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);
}

Спасибо.

Ответы [ 5 ]

11 голосов
/ 05 февраля 2009

Как насчет написания двух методов расширения:

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

и

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

Выглядит чище для меня.

Если между ними есть какой-то общий код, выделите его в отдельный метод.

7 голосов
/ 05 февраля 2009

Заставьте Contact и Person реализовать общий интерфейс - скажем, IContactWithPhoneNumbers - и затем напишите метод расширения "для этого интерфейса".

public interface IContactWithPhoneNumbers {}
public class Contact : IContactWithPhoneNumbers {}
public class Person : IContactWithPhoneNumbers {}
public static void AddPhoneNumber(this IContactWithPhoneNumbers obj) {}
2 голосов
/ 05 февраля 2009

Чтение ваших комментариев (объекты из SDK и не доступны для редактирования). Я бы, наверное, сделал что-то вроде этого:

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);
    }
}

Я думаю, что наилучшей практикой, когда у вас есть контроль над базовыми объектами, будет реализация общего интерфейса.

0 голосов
/ 08 июня 2017

Если вы не можете изменить Person и Contact, вы можете создать их подкласс и позволить им реализовать общий интерфейс.

В методе расширения вы объявляете общий интерфейс как параметр:

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;}
}
0 голосов
/ 02 июля 2009

Вы можете сделать свой метод расширения универсальным, например ::10000

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;
}

Вы не сможете использовать lock, поскольку «T» не является ссылочным типом, как того требует оператор блокировки », поэтому вам, возможно, придется вернуть какое-то значение.

Если он жалуется на невозможность разрешить метод Phones для типа T, вы можете:

Передайте некоторый делегат функции , который будет принимать тип T, ничего не возвращать и выполнять действие ((T)contact).Phones.Add(pr);.

Или вы можете создать интерфейс, подобный следующему:

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

Затем, когда у вас есть этот интерфейс, вы можете добавить следующее в ваш общий метод расширения:

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

Здесь T по-прежнему является универсальным типом, но теперь у вашего метода AddPhoneNumberToContact есть требование, чтобы, каким бы T он ни был, он наследовал от интерфейса IPhoneable, который вы только что определили как метод Phones (). 1022 *

См. Также Метод расширения C # для общих коллекций .

...