【问题标题】:C# method that accepts multiple objects that have common properties?接受具有共同属性的多个对象的 C# 方法?
【发布时间】:2011-12-14 19:16:48
【问题描述】:

我有几个对象,它们都有一些共同的属性。例如:

对象 A 是 X 类型,它有 10 个属性

对象 B 的类型为 Y,它有 15 个属性

对象 C 是 Z 类型,它有 7 个属性

所有这些对象都具有共同的“名称”、“签名”和“校验和”属性。我正在尝试创建一个静态辅助方法,它可以接受包含“名称”、“签名”和“校验和”属性的任何类型的对象。这是可能的还是我实际上需要三种不同的方法(一个接受每种类型的对象)?

编辑 - 值得一提的是,我没有提到这些对象是通过 Web 服务向我公开的。

【问题讨论】:

  • 这称为“结构类型”,存在于 Scala 等语言中。 C#4 引入了dynamic(它是 not 结构类型),我不知道 C# 是否还有其他技巧可以解决这个问题……标准方法是根据需要添加接口.

标签: c# .net methods structural-typing


【解决方案1】:

您应该将这些属性移动到一个公共基类或接口并使用它。

【讨论】:

  • 噢!我忘了提到这些对象是通过 Web 服务 (SOAP) 向我公开的。这会改变你的建议吗?
  • 您如何使用该服务?这应该没什么区别。
  • 我正在使用 VS 在设置 Web 引用时创建的客户端代理。
  • 没有什么能阻止你编辑 VS 生成的代码,尽管我建议使用部分类来避免你的代码在你希望 VS 重新生成类时丢失。在这种情况下,使用通用接口而不是通用基类可能会更好。
【解决方案2】:

您有两个不错的选择。首先是继承:

public class CommonObject
{
    public string Name;
    public string Signature;
    public string Checksum;
}

public class X : CommonObject
{
    // other properties
}

public class Y : CommonObject
{
    // other properties
}

public class Z : CommonObject
{
    // other properties
}

public static void DoSomething(CommonObject o)
{
    // You can access these values
    if (o.Name == "" || o.Signature == "")
        o.Checksum = 0;
}

这很强大,因为您可以将这些属性设为虚拟,并且每个类都可以覆盖以不同方式处理它们。

第二个选项是使用接口:

public class OtherClass
{
    public static void DoSomething(CommonObject o)
    {
        // code here
    }
}

public interface CommonObject
{
    string Name { get; }
    string Signature { get; }
    string Checksum { get; }
}

public class X : CommonObject
{
    private string _name = "";
    private string _signature = "";
    private string _checksum = "";

    string CommonObject.Name { get { return _name; } }
    string CommonObject.Signature { get { return _signature; } }
    string CommonObject.Checksum { get { return _checksum; } }
}

【讨论】:

  • 方法不能在接口声明中实现。它应该是:static void DoSomething(CommonObject o);
  • 从技术上讲,它不应该出现在我发布的代码中的任何位置。他说他正在使用静态辅助方法。他会把它放在他想要的任何班级。我添加了一个虚拟类来保存它。
【解决方案3】:

我将假设由于这些对象是通过 Web 服务公开的,因此您无法控制对象的定义。它们就是它们,你不能让它们从公共基类或接口继承。有了这个问题的约束,你真的只有两个选择。

如果您使用的是 C# 4.0 或更高版本,则可以使用新的 dynamic 类型。这基本上是一个对象引用,直到运行时才进行任何类型评估。因此,如果您在动态类型上使用的属性或方法不存在,您将获得运行时错误,而不是编译期间的错误。

另一种选择是简单地引用 Object 类型并使用反射来操作属性和方法。那里有很多潜在的丑陋之处。

如果您没有使用 C# 4+,那么我想我会使用这三种单独的方法。虽然您可能会重复一些代码,但我宁愿拥有它,也不愿使用您必须在 c# 3.5 中使用的一堆复杂难以遵循的反射调用-

【讨论】:

  • 非常感谢!这些是我一直在寻找的建议!
【解决方案4】:

可能的...如果您定义一个包含公共方法的公共基类,并使对象A、B 和C 成为基类的子类。然后,您的静态辅助方法可以使用基类作为其参数类型,并且可以将任何子类型传递给它。

【讨论】:

    【解决方案5】:

    对于另一个选项,还有dynamic typing。尽管此选项应该适合您,但我肯定会尝试使用其他人提到的接口或基类。

    【讨论】:

      【解决方案6】:

      我认为界面是您的最佳选择,

      public interface ISomeGoodNameForCommonProperies 
      {
        string Name {get;set;}
        string Signature {get;set;}
        string Checksum {get;set;}
      }
      
      public class X : ISomeGoodNameForCommonProperies 
      {
        string Name {get;set;}
        string Signature {get;set;}
        string Checksum {get;set;}
        ...
      }
      
      public class Y : ISomeGoodNameForCommonProperies 
      {
        string Name {get;set;}
        string Signature {get;set;}
        string Checksum {get;set;}
        ...
      }
      
      public class Z : ISomeGoodNameForCommonProperies 
      {
        string Name {get;set;}
        string Signature {get;set;}
        string Checksum {get;set;}
        ...
      }
      

      那么,您的辅助方法将采用 ISomeGoodNameForCommonProperies

      public object MyHelperMethod(ISomeGoodNameForCommonProperies myObject)
      {
        ...
      }
      

      继承当然可以,但是我会避免使用基类,除非它对您尝试创建的对象有意义。您应该问自己的问题是,X、Y 和 Z 是否可以定义为某种不同的对象 O?如果是这样,请继续创建 O 并从中固有。如果这 3 个共同属性不足以定义逻辑实体,但出于实际原因需要将它们组合在一起,那么接口是您的最佳选择。

      【讨论】:

        【解决方案7】:

        您可以使用inheritance

        【讨论】:

          【解决方案8】:

          解决这个问题有两种方法:

          创建一个具有所有这些通用属性的基类,并从中派生其他属性。

          public abstract class MyBaseClass
          {
              public string Name { get; set; }
              public string Signature { get; set; }
              public int Checksum { get; set; }
          }
          
          public class ClassX : MyBaseClass
          {
              // Add the other properties here
          }
          
          public class ClassY : MyBaseClass
          {
              // Add the other properties here
          }
          
          public class ClassZ : MyBaseClass
          {
              // Add the other properties here
          }
          

          您的辅助方法将有一个 MyBaseClass 类型的参数:

          public void MyHelperMethod(MyBaseClass obj)
          {
              // Do something with obj.Name, obj.Siganture and obj.Checksum
          }
          

          将辅助方法放在 MyBaseClass 中也是一个好主意,但没有参数,因为现在它可以直接访问属性:

          public abstract class MyBaseClass
          {
              public string Name { get; set; }
              public string Signature { get; set; }
              public int Checksum { get; set; }
          
              public void CreateChecksum() // Your helper method
              {
                  Checksum = Name.GetHashCode() ^ Signature.GetHashCode();
              }
          }
          

          然后你可以直接从你的对象中调用它:

          objA.CreateChecksum();
          objB.CreateChecksum();
          objB.CreateChecksum();
          

          或者定义一个你的三个类实现的接口:

          public interface IMyInterface
          {
              string Name { get; set; }
              string Signature { get; set; }
              int Checksum { get; set; }
          }
          
          public class ClassX : IMyInterface
          {
                  public string Name { get; set; }
                  public string Signature { get; set; }
                  public int Checksum { get; set; }
              // Add the other properties here
          }
          
          public class ClassY : IMyInterface
          {
                  public string Name { get; set; }
                  public string Signature { get; set; }
                  public int Checksum { get; set; }
              // Add the other properties here
          }
          
          public class ClassZ : IMyInterface
          {
                  public string Name { get; set; }
                  public string Signature { get; set; }
                  public int Checksum { get; set; }
              // Add the other properties here
          }
          

          您的辅助方法将有一个 IMyInterface 类型的参数:

          public void MyHelperMethod(IMyInterface obj)
          {
              // Do something with obj.Name, obj.Siganture and obj.Checksum
          }
          

          你可以像这样调用 MyHelperMethod

          MyHelperMethod(objA);
          MyHelperMethod(objB);
          MyHelperMethod(objC);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-08-14
            • 1970-01-01
            • 1970-01-01
            • 2019-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-28
            相关资源
            最近更新 更多