代码之家  ›  专栏  ›  技术社区  ›  balexandre

如何将通用扩展方法应用于第三方SDK中的多个不相关类型?

  •  8
  • balexandre  · 技术社区  · 16 年前

    我开始爱上了扩展方法,但我只是不知道如何只为确定的对象类型创建一个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 回复  |  直到 7 年前
        1
  •  11
  •   G S    16 年前

    写两种扩展方法怎么样:

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

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

    我觉得更干净。

    如果两者之间有一些共同的代码,将其提取到一个单独的方法中。

        2
  •  7
  •   Eric Schoonover thSoft    16 年前

    制作 Contact Person 实现公共接口-比如 IContactWithPhoneNumbers -然后为这个接口编写一个扩展方法。

    public interface IContactWithPhoneNumbers {}
    public class Contact : IContactWithPhoneNumbers {}
    public class Person : IContactWithPhoneNumbers {}
    public static void AddPhoneNumber(this IContactWithPhoneNumbers obj) {}
    
        3
  •  2
  •   Eric Schoonover thSoft    16 年前

    正在读取注释(对象来自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);
        }
    }
    

    不过,我认为当您控制底层对象时,最好的做法是实现一个公共接口。

        4
  •  0
  •   Sarah Vessels    15 年前

    您可以将扩展方法设为通用的,例如:

    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”不是lock语句所要求的引用类型,所以您可能需要返回一些值。

    如果它抱怨无法解决T型上的phones方法,您可以:

    通过一些 function delegate 它将采用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()方法。

    也见 C# Extension Method for Generic Collections .

        5
  •  0
  •   Thomas    7 年前

    如果您不能更改人员和联系人,您可以创建他们的子类,并让他们实现公共接口。

    在扩展方法中,您将公共接口声明为参数:

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