我不知道为什么方法GetData()需要一个Type参数,我认为Type是指定对象应该是哪个类/类型。我有一个名为GraphicsPathWrap的结构,通过实现ISerializable使其可序列化。我尝试了以下复制功能:
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。我不明白为什么它是MemoryStream的类型。我认为应该可以将其转换为GraphicsPathWrap?我可以通过使用BinaryFormatter对MemoryStream进行反序列化来解决这个问题,但是当剪贴板不能为我做所有事情时它太荒谬了吗?
谢谢!
编辑:我已经完全模拟了你的情况,当你实现了ISerializable接口并且没有正确地反序列化时,就是在说MemoryStream。
GetData()返回以下场景中的Memory Stream:
[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
}
我希望上面的答案会对你有所帮助
Clipboard.SetDataObject(对象数据)方法名称有点误导,因为它没有特别要求DataObject作为参数,而只是一个必须是Serializable的Object。
您可以尝试直接传递gpw,如下所示:
private void Copy(GraphicsPathWrap gpw){
Clipboard.SetDataObject(gpw);
}
如果GraphicsPathWrap是可序列化的,它应该可以工作。
编辑:经过测试后,事实证明该方法可以双向工作,既可以直接传递Serializable对象,也可以将其封装在DataObject中。我通过检查特定Clipboard方法的.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次成功设置然后获取尝试后,它可能会失败。
如果它失败了就像你描述的那样,即对象是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);
}