我有一些来自某些外部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可以带来更多澄清。
答案 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); }
}
}
如果反射证明太慢,你可以使用表达式树来为此构建委托,但我会坚持一个简单的解决方案来开始。
这样做的好处是你只需要编写一次这个代码 - 但它确实意味着在真实的请求对象周围创建一个包装器,而部分类的答案却没有。