3

我有很多由 svcutil 从一些外部 WSDL 文件生成的类似类。任何类都有一个名为 的Header属性和string属性class name + "1"

例如,我有类:SimpleRequest具有Header属性和SimpleRequest1属性。
另一种是ComplexRequest具有Header财产和ComplexRequest1财产的。

所以,我想为这些类创建一个通用接口。所以,基本上我可以定义类似的东西:

interface ISomeRequestClass {
  string Header;
  // here is some definition for `class name + "1"` properties...
}

是否可以在接口中定义这样的成员?


这是帖子编辑...

这是生成类的示例:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]
public partial class SimpleRequest
{


    public string Header;

    [System.ServiceModel.MessageBodyMemberAttribute(Name="SimpleRequest", Namespace="data", Order=0)]
    public SimpleRequestMsg SimpleRequest1;

    public SimpleRequest()
    {
    }

    public SimpleRequest(string Header, SimpleRequestMsg SimpleRequest1)
    {
        this.Header = Header;
        this.SimpleRequest1 = SimpleRequest1;
    }
}

编辑后 2

我更改了这个烦人的 +1 属性的定义以表示真实的实际图片。它都有不同的类类型。那么如何将其拉出到通用界面呢?


编辑后 3

这是可以带来更多澄清的耦合问题。

4

5 回答 5

3

编辑(在看到您的代码示例之后):从技术上讲,您的代码没有Header property,它有一个Header field。这是一个重要的区别,因为您不能在 interface 中指定字段。但是,使用下面描述的方法,您可以将属性添加到返回字段值的类中。


是否可以在接口中定义这样的成员?

不,接口名称不能是动态的。无论如何,这样的界面不会很有用。如果你有一个 class 的实例ISomeRequestClass,你会用什么名字来访问那个属性?

但是,您可以使用显式接口实现:

interface ISomeRequestClass {
    string Header { get; set; }
    string ClassName1 { get; set; }
}

class SomeClass : ISomeRequestClass {
     string Header { ... }

     string SomeClass1 { ... }

     // new: explicit interface implementation
     string ISomeRequestClass.ClassName1 {
          get { return SomeClass1; }
          set { SomeClass1 = value; }
     }
}
于 2012-04-26T08:34:17.907 回答
3

您可以更一般地定义您的界面:

interface ISomeRequestClass {
  string HeaderProp {get; set;}
  string Prop {get; set;}
}

您的具体类可以通过将接口成员映射到类字段来扩展(在额外的代码文件中),如下所示:

public partial class SimpleRequest : ISomeRequestClass
{
  public string HeaderProp
  {
    get
    {
      return Header;
    }
    set
    {
      Header = value;
    }
  }

  public string Prop
  {
    get
    {
      return SimpleRequest1;
    }
    set
    {
      SimpleRequest1= value;
    }
  }
}
于 2012-05-03T22:17:38.510 回答
2

暂时搁置类和属性的命名。

如果您希望创建一个具有与您的特定 +1 类型相关的属性的界面,您有几个选择。

为您的 +1 使用基类

如果您的两个 +1 类都继承自同一个基类,您可以在接口定义中使用它:

public interface IFoo
{
 [...]
 PlusOneBaseType MyPlusOneObject{get;set;}
}

在您的界面上创建一个通用属性

此方法允许您将 +1 属性的类型指定为泛型参数:

public interface IFoo<TPlusOneType>
{
 [...]
 TPlusOneType MyPlusOneObject{get;set;}
}

您可能会使用如下:

public class SimpleRequest : IFoo<SimpleRequest1>
{
 [...]
}

更新

鉴于您的类是部分类,您总是可以创建第二个(非机器生成的)版本的部分类来暗示您的接口。

于 2012-04-26T08:36:05.107 回答
2

您提到了 svcutil,所以我假设您将这些类用作 WCF DataContracts?

如果是这种情况,那么您可以利用name.DataMemberAttribute

interface IRequest 
{
    string Header { get; set; }
    string Request1 { get; set; }
}

[DataContract]
class SimpleRequest : IRequest
{
    [DataMember]
    public string Header { get; set; }

    [DataMember(Name="SimpleRequest1"]
    public string Request1 { get; set; }
}

[DataContract]
class ComplexRequest : IRequest
{
    [DataMember]
    public string Header { get; set; }

    [DataMember(Name="ComplexRequest1"]
    public string Request1 { get; set; }
}

如果您担心在将来某个时间重新生成代码时会给自己做更多的工作,那么我建议您编写一个 PowerShell 脚本来自动执行此转换。毕竟 svcutil 只是微软某个人编写的脚本。这不是魔术或“正确”或“标准”。您的脚本可以调用 scvutil,然后对生成的文件进行一些快速更改。

 

编辑(看到你的编辑后)

您已经在使用MessageBodyMemberAttribute' 的Name属性,所以只需更改此:

public string SimpleRequest1; 

public string Request1; 
于 2012-04-26T08:57:00.243 回答
0

你真的需要这些类有一个通用的接口吗?我很想创建一个包装器接口(或只是一个具体的类),然后可以使用反射来访问相关字段:

// TODO: Make this class implement an appropriate new interface if you want
// to, for mocking purposes.
public sealed class RequestWrapper<TRequest, TMessage>
{
    private static readonly FieldInfo headerField;
    private static readonly FieldInfo messageField;

    static RequestWrapper()
    {
        // TODO: Validation
        headerField = typeof(TRequest).GetField("Header");
        messageField = typeof(TRequest).GetField(typeof(TRequest).Name + "1");
    }

    private readonly TRequest;

    public RequestWrapper(TRequest request)
    {
        this.request = request;
    }

    public string Header
    {
        get { return (string) headerField.GetValue(request); }
        set { headerField.SetValue(request, value); }
    }

    public TMessage Message
    {
        get { return (TMessage) messageField.GetValue(request); }
        get { messageField.SetValue(request, value); }
    }
}

如果反射证明太慢,您可以使用表达式树为此构建委托,但我会坚持从一个简单的解决方案开始。

这样做的好处是您只需要编写一次此代码 - 但这确实意味着围绕真实的请求对象创建一个包装器,而部分类的答案却没有。

于 2012-05-09T05:55:12.037 回答