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

我有一些来自某些外部WSDL文件的svcutil生成的类似类。 任何类都有一个Header属性和string属性,它名为class name + "1"

例如,我有类:具有Header属性和SimpleRequest1属性的SimpleRequest1
另一个是具有Header属性和ComplexRequest1属性的ComplexRequest1

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

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

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


这是post编辑去…

以下是生成的类的示例:

 [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

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

编辑 (看到你的代码示例后):从技术上讲,你的代码没有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; } } } 

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

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

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

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

使用+ 1的基类

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

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

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

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

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

您可以使用哪个:

 public class SimpleRequest : IFoo { [...] } 

更新

鉴于您的类是部分类,您可以始终创建部分类的第二个(非机器生成的)版本,它可以实现您的界面。

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

如果是这种情况,那么您可以使用DataMemberAttributename属性。

 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; 

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

 // TODO: Make this class implement an appropriate new interface if you want // to, for mocking purposes. public sealed class RequestWrapper { 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); } } } 

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

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