getdata()返回一个MemoryStream类型的对象

本文关键字:类型 对象 MemoryStream 返回 getdata 一个 | 更新日期: 2023-09-27 18:03:17

我不知道为什么方法GetData()需要Type的参数,我认为Type是指定对象应该是哪个类/类型。我有一个叫做GraphicsPathWrap的结构,它通过实现isserializable来序列化。我尝试了以下复制函数:

private void Copy(GraphicsPathWrap gpw){
  DataObject obj = new DataObject();
  obj.SetData(typeof(GraphicsPathWrap), gpw);
  Clipboard.SetDataObject(obj);
}

然后尝试下面的粘贴函数:

private GraphicsPathWrap Paste()
{
  return (GraphicsPathWrap)Clipboard.GetDataObject().GetData(typeof   (GraphicsPathWrap));
}

它应该工作,但是GetData(…)返回一个MemoryStream类型的对象,并且抛出InvalidCastException。我不明白为什么它是记忆流的类型。我认为它应该能够被转换为GraphicsPathWrap?我可以通过使用BinaryFormatter来反序列化MemoryStream来解决这个问题,但当剪贴板不能为我做所有的事情时,这太荒谬了?

谢谢!

getdata()返回一个MemoryStream类型的对象

编辑:我已经完全模拟了你的情况,事情是说MemoryStream当你已经实现了isserializable接口,并没有正确地反序列化它。

GetData()在以下场景中返回内存流:

      [Serializable]
        public struct GraphicsPathWrap : ISerializable
        {
            private static string myValue = "This is the value of the class";             
            // Creates a property to retrieve or set the value. 
            public string MyObjectValue
            {
                get
                {
                    return myValue;
                }
                set
                {
                    myValue = value;
                }
            }
            #region ISerializable Members
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
            }
            #endregion
        } 

然后,当GetData()给出正确的类型对象时,我正确地实现了序列化'反序列化

[Serializable]
        public struct GraphicsPathWrap : ISerializable
        {
            private static string myValue = "This is the value of the class";
            public GraphicsPathWrap(SerializationInfo info, StreamingContext ctxt)  // Deserialization Constructor
            {
                myValue = (string)info.GetValue("MyValue", typeof(string));
            }
            // Creates a property to retrieve or set the value. 
            public string MyObjectValue
            {
                get
                {
                    return myValue;
                }
                set
                {
                    myValue = value;
                }
            }
            #region ISerializable Members
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("MyValue", myValue); // Serialize the value
            }
            #endregion
        }

希望以上答案能对你有所帮助

剪贴板。SetDataObject(object data)方法名有点误导人,因为它并没有特别要求将数据对象作为参数,而只是一个必须是可序列化的对象。

你可以像这样直接传递gpw:

private void Copy(GraphicsPathWrap gpw){
  Clipboard.SetDataObject(gpw);
}

如果GraphicsPathWrap是可序列化的,它应该可以工作。

编辑:在我自己测试之后,结果证明该方法可以两种方式工作,要么直接传递Serializable对象,要么将其封装在DataObject中。我通过检查。net源代码的特定剪贴板方法来确认它,在那里我发现了这个:

if (data is DataObject) 
{
      dataObject = (DataObject)data; 
}

因此,正如Ramesh在另一个答案中所说,您可能想要检查您的对象是否正确地设置为Seriaizable

我使用Clipboard.GetData类型的对象SerializedClipboardFragment -这是我自己的类型,一个类,我用[Serializable()]属性标记:

[Serializable()]
public class SerializedClipboardFragment
{
    readonly string[] m_ancestors;
    readonly string m_fragment;
    readonly int m_numberOfNodes;
    readonly bool m_isInsertingBlock;
    readonly bool m_isInsertingTable;
    public SerializedClipboardFragment(
        string[] ancestors,
        string fragment,
        int numberOfNodes,
        bool isInsertingBlock,
        bool isInsertingTable
        )
    {
        m_ancestors = ancestors;
        m_fragment = fragment;
        m_numberOfNodes = numberOfNodes;
        m_isInsertingBlock = isInsertingBlock;
        m_isInsertingTable = isInsertingTable;
    }
    internal static DataFormats.Format s_format;
    static SerializedClipboardFragment()
    {
        s_format = DataFormats.GetFormat(typeof(SerializedClipboardFragment).FullName);
    }
    ... etc -- various get-only properties ...
}

从剪贴板获取数据的代码如下:

    public static SerializedClipboardFragment getSerializedFragment()
    {
        if (!Clipboard.ContainsData(SerializedClipboardFragment.s_format.Name))
        {
            return null;
        }
        object o = Clipboard.GetData(SerializedClipboardFragment.s_format.Name);
        return (SerializedClipboardFragment)o;
    }

当我测试时,我发现通常工作。

但它有时在我的自动回归测试中失败,我试图在设置后立即从剪贴板获取数据…例如,它可能在连续30次成功的set-then-get尝试后失败。

如果失败,就像你描述的那样,即对象是MemoryStream

注意它不应该失败,因为Clipboard.ContainsData最近返回了true

我意识到只有一个系统剪贴板;当我运行这个测试时,我的手离开键盘,当这个过程发生时,我不想干扰剪贴板。

无论如何,如果我这样写代码,问题似乎就消失了:

    public static SerializedClipboardFragment getSerializedFragment()
    {
        if (!Clipboard.ContainsData(SerializedClipboardFragment.s_format.Name))
        {
            return null;
        }
        // sometimes return MemoryStream object instead under automated-testing
        // possibly a timing problem
        object o = null;
        for (int i = 0; i < 10; ++i)
        {
            o = Clipboard.GetData(SerializedClipboardFragment.s_format.Name);
            if (o is SerializedClipboardFragment)
                return (SerializedClipboardFragment)o;
            System.Threading.Thread.Sleep(100);
        }
        return (SerializedClipboardFragment)o;
    }

所以除非我弄错了,这可能是一些令人讨厌的计时错误,与在剪贴板中存储自定义数据类型有关。

[DataObject(true)]
    public class EmployeeDAL
    {
        [DataObjectMethod(DataObjectMethodType.Update, true)]
        public int UpdateEmployeeSalary(int percentage, int deptid, int posid)
        {
            OracleConnection con = new OracleConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            OracleCommand cmd = new OracleCommand("GIVE_RAISE_SP", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("PV_PERCENTAGE_RAISE_I", OracleType.Int32).Value = percentage;
            cmd.Parameters.AddWithValue("PV_POSITIONID_I", OracleType.Int32).Value = posid;
stac            cmd.Parameters.AddWithValue("PV_DEPTID_I", OracleType.Int32).Value = deptid;
            cmd.Parameters.AddWithValue("PV_NUM_EMPLOYEES_O", OracleType.Int32).Direction = ParameterDirection.Output;
            OracleDataAdapter da = new OracleDataAdapter(cmd);
            try
            {
                con.Open();
                da.UpdateCommand = cmd;
                cmd.ExecuteNonQuery();
            }
            catch (Exception)
            {
            }
            finally
            {
                con.Close();
            }
            return Convert.ToInt32(cmd.Parameters["PV_NUM_EMPLOYEES_O"].Value);
        }