不按名称指定接口成员,而是键入

时间:2012-04-26 08:28:25

标签: c# .net oop class interface

我有一些来自某些外部WSDL文件的svcutil生成的类似类。任何类都有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;
    }
}

POST EDIT 2

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


POST EDIT 3

以下coupled question可以带来更多澄清。

5 个答案:

答案 0 :(得分:3)

编辑(在看到您的代码示例后):从技术上讲,您的代码没有Header 属性,它有一个Header 字段。这是一个重要的区别,因为you cannot specify fields in an interface。但是,使用下面描述的方法,您可以向返回字段值的类添加属性。


  

是否可以在界面中定义这样的成员?

不,接口名称不能是动态的。无论如何,这样的界面不会很有用。如果您有一个类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; }
     }
}

答案 1 :(得分: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;
    }
  }
}

答案 2 :(得分: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>
{
 [...]
}

<强>更新

鉴于您的类是部分类,您总是可以创建第二个(非机器生成的)部分类版本,这个版本会影响您的界面。

答案 3 :(得分:2)

你提到过svcutil所以我假设你使用这些类作为WCF DataContracts?

如果是这种情况,那么您可以使用name的{​​{1}}属性。

DataMemberAttribute

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

编辑(看到您的编辑后)

您已使用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; } } 的{​​{1}}媒体资源,因此请更改此内容:

MessageBodyMemberAttribute

Name

答案 4 :(得分: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); }
    }
}

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

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