【问题标题】:Generics or just use overloads?泛型还是只使用重载?
【发布时间】:2012-01-05 14:57:50
【问题描述】:

我有 3 个类,都具有相似的属性。在所有 3 个类中,其中 3 个属性的名称完全相同。与其编写 3 个方法(每个类一个),有什么方法可以在这里利用泛型吗?

public static String GetAString(ActivityMedia activityMedia)
{
   return activityMedia.name;
}

public static String GetAString(AuditMedia auditMedia)
{
   return auditMedia.name;
}

public static String GetAString(VehicleMedia vehicleMedia)
{
   return vehicleMedia.name;
}

编辑:显然是为了简单地将这 3 种类类型之一的对象传递给 GetAString()

【问题讨论】:

  • 这些类是否共享一个接口?
  • 是否可以选择为这些类提供一个通用的Media 超类或接口?
  • 他们不共享一个接口号。它们只是完全独立的类。

标签: c# oop class generics overloading


【解决方案1】:
  1. 使用单个 string Name 属性引入接口
  2. 按接口标记所有三个类
  3. 现在您可以直接评估媒体名称我不知道为什么您需要一个方法,但无论如何,您可以为接口类型创建扩展方法IMedia
interface IMedia
{
    string Name { get; }
}

class ActivityMedia : IMedia
class AuditMedia : IMedia
class VehicleMedia : IMedia

static class MediaExtensions
{
   public static string GetName(this IMedia instance)
   {
          return instance.Name;
   }
}

【讨论】:

  • 如果您使用接口,您不认为在所有 ActivityMedia、AuditMedia、VehicleMedia 类上实现 Name 属性是多余的吗?虽然界面有不同的用途
  • 你不需要实现它,因为这三个媒体都已经有了 Name 属性,这就是我们说的标记接口
  • 它的副本,不是吗?你说什么?
【解决方案2】:

另一种选择是使用接口...

public interface INameable
{
   String Name { get; }
}

public static String GetAString(INameable nameable)
{
   return nameable.Name;
}

虽然此时您可能甚至不需要 GetAString 方法?

【讨论】:

    【解决方案3】:

    你可以通过界面来做到这一点

    public interface INamedMedia
    {
        string Name { get; }
    }
    

    那么你的方法就变成了

    public static String GetAString(INamedMedia media)
    {
        return media.Name;
    }
    

    你的类实现INamedMedia

    public class Media : INamedMedia
    {
        public string Name { get { return "Media"; } }
    }
    

    【讨论】:

      【解决方案4】:

      我原以为界面会是这里的理想解决方案:

      public interface IMedia
      {
          public String Name { get; }
      }
      

      然后你可以让你的静态方法将该接口类型作为它的参数:

          public static String GetAString(IMedia media)
          {
              return media.Name;
          }
      

      或者您的所有媒体类都可以派生自包含您需要的属性的基类型,并将其传递给方法而不是接口。

      很难告诉您哪个是更好的选择,因为这取决于您的应用程序的复杂性和继承链。

      这个article可能会有所帮助

      【讨论】:

        【解决方案5】:

        如果它们完全不相关,一种选择是使用dynamic(如果您使用的是 C# 4):

        public static String GetAString(dynamic d){
            return d.name;
        }
        

        编辑:

        如果你没有使用 C# 4.0,你可以使用反射:

        public static string GetAString(object o)
        {
            System.Reflection.PropertyInfo name = o.GetType().GetProperty("name");
            return (string) name.GetValue(o, null);
        } 
        

        【讨论】:

        • 不幸的是,我们还没有达到 4。如果我们是的话,那看起来像是完美的解决方案。我会调查一下。
        • 哪里提到了 .NET 4?
        • 或者,您可以使用反射。
        • 我不明白这个讨论的去向!?如果我在 C# 4 中编码,Vlad 已经提出了一个解决方案,仅此而已。
        • @ChrisBD : 很明显你来这里是一个 bti 之后所以没有指定 if .NET 4... 就无法看到原始答案
        【解决方案6】:

        您不需要泛型,您需要 OOP 和继承。

        ActivityMediaAuditMediaVehicleMedia 全部设为实现IMedia 之类的基本接口或派生MediaBase 之类的基本类

        然后您只编写一次方法GetAString,它接受IMedia 对象或MediaBase 对象。

        另一种选择可能是您在ActivityMediaAuditMediaVehicleMedia 中覆盖默认的ToString 方法,以便只返回名称属性,然后您只需调用ToString 而无需任何@987654334 @方法。

        【讨论】:

          【解决方案7】:

          如果这些类没有共同的祖先,泛型将无法帮助您。解决方案是通过声明具有name 属性的接口来安排它们共享共同祖先。让每个类都实现该接口,然后您就可以拥有一个GetAString 函数。

          【讨论】:

            【解决方案8】:

            如果这三个类具有相同属性的子集,则最好实现一个基类,而不是在派生三个媒体类的基类中声明的公共属性和方法。

            public class ActivityMedia : Media 
            {
            
            }
            
            public class Media
            {
                 public string Name {get;set;}
            }
            

            这样三个类在一个地方定义了一组方法,使得代码更容易维护。同时让您可以灵活地将特定于类的方法放入其派生实现中。

            【讨论】:

              【解决方案9】:

              这里实现继承比泛型更符合逻辑。

              您也可以使用Interface,但这会使您的Name 属性在您的所有ActivityMediaAuditMediaVehicleMedia 类上重复。

              考虑一个基类Media

              public class Media
              {
                  // consider all properties that are common
                  // on Media domain
                  public string Name { get; set }
              }
              

              并从Media类继承ActivityMediaAuditMediaVehicleMedia

              public class ActivityMedia : Media
              {
                  // other properties on ActivityMedia domain
              }
              
              public class AuditMedia : Media
              {
                  // other properties on AuditMedia domain
              }
              
              public class VehicleMedia : Media
              {
                  // other properties on VehicleMedia domain
              }
              

              现在在您的 GetAString 方法上使用 Media

              public static String GetAString(Media activityMedia)
              {
                 return activityMedia.name;
              }
              
              public static String GetAString(Media auditMedia)
              {
                 return auditMedia.name;
              }
              
              public static String GetAString(Media vehicleMedia)
              {
                 return vehicleMedia.name;
              }
              

              【讨论】:

              • 继承有时是个魔鬼,当你想在三个类之间共享单个属性时,通过基类(而且不是抽象的)来实现是个坏主意
              【解决方案10】:

              这就是继承来拯救你的地方。有这样的基类:

              public class Media
              {
                  public string name { get { return "Media"; } }
              }
              

              那么每个类都会继承并定义自己的名字:

              public class ActivityMedia : Media
              {
                  public new string name { get { return "Activity Media"; } }
              }
              

              最后:

              public static String GetAString(Media media)
              {
                  return media.name;
              }
              

              编辑:当您坚持当前的设计时,您可以使用反射:

              public static String GetAString(object media)
              {
                  PropertyInfo propName = media.GetType().GetProperty("name");
                  if (propName != null)
                      return propName.GetValue(media, null);
                  return "";
              }
              

              【讨论】:

              • 我不会决定重新设计这些类以从媒体类继承。我现在几乎坚持使用单独的类。我明白你的意思,我把它作为答案的其他地方。
              • 查看我的编辑,无论对象类型是什么,它都会查找名为“name”的属性并获取其值。
              猜你喜欢
              • 2011-02-04
              • 2012-04-12
              • 1970-01-01
              • 2022-11-18
              • 2021-04-23
              • 2012-12-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多