C# 在DataPackage.SetData或DataPackage.GetDataAsync之后处置irandomaccesstream?

C# 在DataPackage.SetData或DataPackage.GetDataAsync之后处置irandomaccesstream?,c#,windows,clipboard,data-transfer,data-sharing,C#,Windows,Clipboard,Data Transfer,Data Sharing,考虑使用SetData将数据放入windows剪贴板数据包,然后使用GetDataAsync检索数据,如下所示: IEnumerable<T> objects = ...; var randomAccessStream = new InMemoryRandomAccessStream(); using (XmlDictionaryWriter xmlWriter = XmlDictionaryWriter.CreateTextWrit

考虑使用SetData将数据放入windows剪贴板数据包,然后使用GetDataAsync检索数据,如下所示:

        IEnumerable<T> objects = ...; 
        var randomAccessStream = new InMemoryRandomAccessStream();
        using (XmlDictionaryWriter xmlWriter = XmlDictionaryWriter.CreateTextWriter(randomAccessStream.AsStreamForWrite(), Encoding.Unicode)) {
            var serializer = new DataContractSerializer(typeof(T), knownTypes);
            foreach (T obj in objects) {
                serializer.WriteObject(xmlWriter, obj);
            }
        }
        dataPackage.SetData(formatId, randomAccessStream);
我的问题是,我什么时候处理随机访问流?我已经做了一些搜索,我看到的所有使用SetData和GetDataAsync的示例对于处理放入数据包或从数据包中获取的对象完全没有任何作用

我应该在SetData之后、GetDataAsync之后、DataPackage.OperationCompleted中、以这些的某种组合处理它,还是不处理它们

sjb

另外,如果我能在这里挤出第二个问题。。。当我使用例如DataPackage.Properties.Add(“IEnumerable”,entities)将引用放入数据包时,是否会产生安全风险?其他应用程序是否可以访问该引用 使用它

我何时处理随机存取流

仅当您使用完流后才对其进行处置,当您使用该流时,它将不再在任何其他上下文中可用,即使您在其他对象实例中存储或传递了对它的多个引用

如果您谈论的是
SetData()
逻辑中引用的原始流,那么从另一个角度来看,如果您过早地处理,则使用代码将无法访问该流,并且将失败

作为一般规则,我们应该尝试设计逻辑,以便在任何给定的时间点,任何给定流都有一个明确的单一所有者,这样就应该清楚谁负责处理流。这个对稍微不同的场景的响应很好地解释了这一点,但是作为一般模式,只有创建流的范围才应该负责处理它

  • 一个例外是,如果您需要在创建方法之外访问流,那么父类应该持有对它的引用,在这种情况下,您应该使父类实现
    IDisposable
    ,并确保它清除可能挂起的任何资源
您在文档中看不到这一点的原因通常是调用
Dispose()
的时间上的细微差别超出了范围,或者会在为其他目的而设计的示例中丢失

  • 特别是对于通过任何机制传递流并随后使用流的示例,如使用
    DataPackage
    ,很难显示所有编排代码,以覆盖使用
    DataPackage.SetData(…)
    存储流与稍后通过
    DataPackage.GetDataAsync(…)
    访问流之间的时间
  • 还考虑了 DATAPACKEAGE /代码>的最常见场景,其中消费者不仅在不同的逻辑范围内,而且最可能在完全不同的应用程序域中,包括所有的代码以覆盖何时或如果要调用DISSION应包含2个不同应用程序的整个代码库。
tldr 剪贴板设计用于在应用程序之间传递内容,并且只能传递字符串内容或对文件的引用,所有其他内容必须序列化为字符串或保存到文件,或者必须表现为文件,才能通过剪贴板跨应用程序域访问

通过剪贴板传递自定义数据和格式有支持和指导,最终这涉及到围绕“如何在提供者端准备内容”和“如何在消费者端解释内容”的离散管理。如果可以为此使用简单序列化,那么

然后在可能完全不同的应用中:

string formatId = "MyCustomFormat";
var dataPackageView = Clipboard.GetContent();
object content = await dataPackageView.GetDataAsync(formatId);
string contentString = content as string;
var objectsOut = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<Test>>(contentString);

foreach (var o in objectsOut)
{
    Console.WriteLine(o);
}

有什么想法吗,伙计们?把你得到的每一条小溪都处理掉。如果您不这样做,这应该不是一个大问题,因为这些流中的大多数(所有?)都在内存中,因此,如果它们一直保留到下一个GCA,这没什么大不了的,因为这是so的一般规则,您现在已经知道了;),不,您不能再问第二个问题。如果您担心某些第三方插件会记录您的数据或尝试与存储在剪贴板中的数据交互,请不要使用它。对象引用是否容易以这种方式截获和使用,这取决于
T
的定义,你能做到吗,是的,这是一个漏洞吗,是的,你能从这些信息中获得很多价值吗,这真的取决于,使用流会带来同样的风险,只是稍微少一点努力
DataPackage
本身就是一种风险,从设计上讲,它允许您跨应用程序域传递数据。通过调用
SetData()
我不介意他们获取我放在剪贴板上的数据,我只是不希望他们在我的内存中爬行。我不清楚的是其他价格是否可以访问我的内存。是的,关于第二个问题,我非常理解物体所有权和处置等的重要性。但是,我在这里问的问题是另一个问题。当流进入SetData,然后使用GetDataAsync返回时,无论是在同一进程中还是在不同的进程中,返回的内存引用是否与进入的内存引用相同?或者剪贴板是否在SetData中序列化流,然后在GetDataAsync中重建/反序列化流?GetDataAsync是从同一个进程调用还是从另一个进程调用重要吗?这是一个剪贴板问题,不是关于一般的dispose。请注意,我不能将任何旧对象放在剪贴板中,SetData(但不是属性)的使用受到严格限制。关键是您无法序列化流。您可以对其进行读取或写入,但不能将其持久化为文件,然后重新加载。基本上,不要试图以这种方式使用剪贴板,它不是为这样使用而设计的。是的,在您的本地上下文中,对象引用在某些上下文中是持久的,但它不能被依赖,尤其是跨应用程序域边界的引用。如果你的代码有效,做得很好,但是
IEnumerable<Test> objectsIn = new Test[] { new Test { Name = "One" }, new Test { Name = "two" } };
var dataPackage = new DataPackage();
dataPackage.SetData("MyCustomFormat", Newtonsoft.Json.JsonConvert.SerializeObject(objectsIn));
Clipboard.SetContent(dataPackage);

...

var dataPackageView = Clipboard.GetContent();
string contentJson = (await dataPackageView.GetDataAsync("MyCustomFormat")) as string;
IEnumerable<Test> objectsOut = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<Test>>(contentJson);
IEnumerable<Test> objectsIn = new Test[] { new Test { Name = "One" }, new Test { Name = "two" } };

var dataPackage = new DataPackage();
string formatId = "MyCustomFormat";

var serial = Newtonsoft.Json.JsonConvert.SerializeObject(objectsIn);
dataPackage.SetData(formatId, serial);
Clipboard.SetContent(dataPackage);
string formatId = "MyCustomFormat";
var dataPackageView = Clipboard.GetContent();
object content = await dataPackageView.GetDataAsync(formatId);
string contentString = content as string;
var objectsOut = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<Test>>(contentString);

foreach (var o in objectsOut)
{
    Console.WriteLine(o);
}
public class Test
{
    public string Name { get; set; }
}