接受具有共同属性的多个对象的C#方法?

3
我有几个对象,它们有一些共同的属性。例如: 对象A是X类型并且拥有10个属性。 对象B是Y类型并且拥有15个属性。 对象C是Z类型并且拥有7个属性。 这些对象都有"名称"、"签名"和"校验和"等属性共同存在。我试图创建一个静态的帮助方法来接受任何包含“名称”,“签名”和“校验和”属性的类型的对象。这可能吗?或者我需要三个不同的方法(分别用于接受每种类型的对象)? 注:值得一提的是,我暴露在Web服务中的是这些对象。

1
这被称为“结构类型”,并存在于像Scala这样的语言中。C#4引入了dynamic(它不是结构类型),我不知道C#是否还有其他技巧...标准方法是根据需要添加接口。 - user166390
8个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
8
你应该将这些属性移动到一个公共的基类或接口中,并使用它。

糟糕!我忘记提到这些对象是通过Web服务(SOAP)向我公开的。这是否改变了您的建议? - bmt22033
你是怎么使用这个服务的?这不应该有所影响。 - SLaks
我正在使用一个客户端代理,这是在设置网络引用时由VS创建的。 - bmt22033
2
没有任何阻止你编辑VS生成的代码,但我建议使用部分类来避免在你想要VS重新生成类时丢失你的代码。在那种情况下,你可能最好使用一个公共接口而不是一个公共基类。 - Brian

4

你有两个很好的选择。第一个是继承:

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); - Olivier Jacot-Descombes
从技术上讲,我发布的代码中不应该有任何地方出现它。他说他正在使用静态辅助方法。他可以将其放在任何他想要的类中。我添加了一个虚拟类来保存它。 - Trevor Elliott

3
我假设由于这些对象是通过Web服务公开的,因此您无法控制对象的定义。它们就是它们本身,您无法让它们继承自公共基类或接口。在这种问题的限制下,您真正只有两个选择。 如果您使用的是C# 4.0或更高版本,则可以使用新的dynamic类型。基本上,这是一个对象引用,直到运行时才进行任何类型评估。因此,如果您在动态类型上使用的属性或方法不存在,您将获得运行时错误而不是编译期错误。 另一个选择是简单地获取Object类型的引用并使用反射来操作属性和方法。可能会有很多潜在的丑陋代码。 如果您不使用C# 4+,那么我认为我会选择三个单独的方法。虽然您可能会重复一些代码,但我宁愿这样做,也不要使用C# 3.5-中必须使用的一堆复杂难以跟踪的反射调用。

非常感谢!这些正是我在寻找的建议! - bmt22033

2

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


2

另外一个选择是使用动态类型。虽然这个选项可能适合您,但我强烈建议像其他人提到的那样使用接口或基类。


2

我认为接口是您的最佳选择,尤其是在IT技术方面。请保留HTML标签。

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并从中继承。如果这三个共同拥有的属性不足以定义一个逻辑实体,但出于实际原因需要将它们分组在一起,则接口是最佳选择。


1

1

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

创建一个基类,其中包含所有这些共同属性,并从中派生其他类。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,