叫不上名字,但类型指定接口成员(Specify interface member not by na

2019-09-16 19:03发布

我有很多来自一些外部WSDL文件由SvcUtil工具生成的类似的类的。 任何类有一个Header属性和string ,其命名属性class name + "1"

举例来说,我有类: SimpleRequestHeader财产和SimpleRequest1财产。
另一个是ComplexRequestHeader财产和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;
    }
}

POST EDIT 2

我改变了这个恼人的+1属性的定义,以真正代表实际的画面。 这是所有有不同的类类型。 所以,我怎么也拔不出来常用的接口?


帖子编辑3

这里是加上的问题 ,这会带来更多的澄清。

Answer 1:

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


是否有可能在界面来定义这样的会员吗?

不,接口名称不能是动态的。 无论如何,这样的接口不会是非常有用的。 如果你有类的实例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; }
     }
}


Answer 2:

你可以更普遍地定义你的界面:

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


Answer 3:

撇开了片刻类和属性的命名。

如果您正在寻找创建您的具体+1类型相关的属性的接口,你有几个选项。

使用一个基类为您的+1

如果两个+1类从同一个基类继承,你可以在你的接口定义使用:

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

创建接口的通用属性

这种方法允许你指定类型为+1属性作为泛型参数:

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

您可能需要使用这样的:

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

更新

鉴于你的类是局部类,你总是可以创建一个第二(产生的非机)是impliments你的接口部分类的版本。



Answer 4:

你提到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再做出几个简单的修改后的文件。

 

编辑 (看到你的编辑后)

你已经在使用MessageBodyMemberAttributeName属性,因此只是改变这一点:

public string SimpleRequest1; 

public string Request1; 


Answer 5:

你真的需要这些类有共同的接口? 我会被诱惑,而不是创建一个包装接口(或只是一个具体的类),然后可以使用反射来访问有问题的领域:

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

你可以使用表达式目录树建立代表这个如果反射证明太慢,但我会坚持一个简单的解决方案开始。

这样做的好处是,你只需要一次写这样的代码 - 但它确实意味着创造周围的真实的请求对象,其中部分类的答案没有一个包装。



文章来源: Specify interface member not by name but type