代码之家  ›  专栏  ›  技术社区  ›  bwerks

wcf:是否可以序列化通用接口?

  •  6
  • bwerks  · 技术社区  · 14 年前

    我试图实现一个服务契约,它包含一个采用通用接口的方法,并且该通用接口本身被赋予了一个接口参数。我已经用ServiceKnownType修饰了服务接口,用常规KnownType修饰了服务实现,用常规KnownType修饰了DataContract实现:

    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))]
    [ServiceKnownType(typeof(Batch<object>))]
    [ServiceKnownType(typeof(Command))]
    public interface IActions
    {
        [OperationContract]
        IResponse TakeAction(IBatch<ICommand> commands);
    }
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
    [KnownType(typeof(Batch<object>))]
    [KnownType(typeof(Command))]
    internal class Actions : IActions
    {
    }
    
    [DataContract]
    [KnownType(typeof(Command))]
    public class Batch<T> : IBatch<T>
    {
    }
    

    对于记录,我在那里有一个批处理,因为您似乎只能为一个泛型类型表达一次knownType——它似乎会发出batchofanyType,但我不确定如何处理它。

    我得到的例外情况是“将静态未知的任何类型添加到已知类型列表中-例如,使用knowntypeattribute属性或将其添加到传递给DataContractSerializer的已知类型列表中。”

    有什么明显的我做错了吗?只是不支持接口的通用接口吗?作为记录,我在这个项目的C 2.0和.NET 3.0上。

    4 回复  |  直到 11 年前
        1
  •  12
  •   Thorarin    14 年前

    如果您真的想要,您可以在服务契约定义中使用接口,只要您包括您正在进行的已知类型(稍作调整,请参见下文)。

    显然,使用一个接口作为泛型类型参数对C 3.0来说是一个过桥。我将已知的类型属性更改为

    [ServiceKnownType(typeof(Batch<Command>))]
    public interface IActions
    {
    }
    

    在某种程度上,这使它起作用。序列化和反序列化本身将起作用,但随后您将面临以下异常:

    无法强制转换“batch`1[命令]”类型的对象 键入'ibatch'1[icommand]'。

    要使该类型转换起作用,您需要对泛型类型协方差的语言支持,这是在C 4.0中引入的。但是,要使它在C 4.0中工作,您需要添加一个方差修饰符:

    public interface IBatch<out T>
    {
    }
    

    然后它就完美地工作了…不幸的是,您没有使用C 4.0。

    在服务契约中使用接口的最后一件事是:如果您要从接口中生成服务引用,它将把所有接口参数键入为 object ,因为原始接口类型不是元数据的一部分。您可以通过程序集引用共享契约,或者手动重构生成的代理来修复它,但总而言之,与WCF一起使用接口可能比它的价值更麻烦。

        2
  •  2
  •   marc_s    14 年前

    WCF是一个基于SOA消息的系统——它可以以可以用XML模式表示的序列化XML格式跨线发送任何内容。

    不幸的是,XML模式既不知道接口也不知道泛型,所以不——您不能一般地序列化它们——您需要使用具体的类型。

        3
  •  1
  •   Mike    14 年前

    无法序列化接口。接口只是定义契约,而不是对象。我想唯一的例外是ISerializable接口。

        4
  •  1
  •   RQDQ    14 年前

    泛型可以序列化,但有一定的限制。例如,给定数据合同:

    [DataContract]
    public class Foo<T>
    {
         [DataMember]
         public T Value { get; set; }
    }
    

    服务合同:

    [ServiceContract]
    public interface IService1
    {
         [OperationContract]
         Foo<String> GetData();
    }
    

    以及服务实现:

    public class Service1 : IService1
    {
       public Foo<string> GetData()
       {
           return new Foo<string>() { Value = "My test string" };
       }
    }
    

    在设置上述服务的服务引用之后,可以运行此代码:

    ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
    
    ServiceReference1.FooOfstring temp = client.GetData();
    
    MessageBox.Show(temp.Value);
    

    并显示带有“我的测试字符串”的消息框。

    注意,服务本身不是通用的,但是使用的数据约定是通用的。此外,在客户端生成的数据协定不是通用的,而是一个“扁平”类,其属性值为string类型:

    [System.Runtime.Serialization.DataMemberAttribute()]
    public string Value 
    { 
       get {...} 
       set {...} 
    }
    
    推荐文章