结构和代表 [英] Structs and delegates

查看:76
本文介绍了结构和代表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一些创建委托的代码。

委托调用结构的成员函数。

代码编译,但有令人惊讶的行为:


使用System;


命名空间ConsoleApplication1

{

public struct SimpleStruct

{

public int i;


public void assignToI(int x)

{

Console.WriteLine(" Assigning i:" + x);

i = x;

Console.WriteLine(" i =" + x);

}

}


class Class1

{

public delegate void Assigner(int s);


private static void callDelegate(Assigner a,int i)

{

a(i);

}


static void Main(string [] args)

{

SimpleStruct s = new SimpleStruct();

s.assignToI(1); //按预期工作,将1分配给

System.Console.WriteLine(调用assignToI =" + si后;


/ /创建一个调用assignToI()的委托

Assigner assign_to_i =新的Assigner(s.assignToI);


//调用辅助函数,传递委托和新值的价值

callDelegate(assign_to_i,99);


System.Console.WriteLine(" si在调用delegate =" + si之后); < br $>
//分配丢失,si仍然包含1 !!!

}

}

}


运行时,此代码打印:


$ ./ConsoleApplication1.exe

分配i:1

i = 1

si调用assignToI = 1

分配i:99

i = 99

si调用delegate后= 1


注意直接调用s.assignToI()按预期工作:

调用后,结构成员有新值。


但是,c所有通过delagate都没有按预期工作:

分配的值丢失,结构成员

具有旧值。

现在,我意识到这里发生了什么。委托构造函数

需要一个类型为object的参数。换句话说,表达


新的Assigner(s.assignToI)


内部转换为类似
的内容>
新代表(s,assignToI)


因此,结构是静默装箱的,当委托运行时,

是什么它指定的是堆上结构的临时副本,

而不是分配给真正的结构。


这里有几个想法:


1)我觉得这很令人惊讶。在我的代码中,我没有通过

结构作为参数,所以我不期望这种行为。 (是的,

我知道结构最终被装箱了,但是代码中的任何地方都没有显示

。)


2)我认为这种行为是错误的。 (是的,我理解*为什么*它

按照它的方式工作,但这并不一定使行为

正确。)代表相当于C ++成员函数指针。

如果我创建一个委托并传递一个struct的方法,我希望

委托在我指定的struct实例上调用该方法,而不是

一些临时副本。


3)即使我们接受行为是正确的,那么为什么编译器

允许我写这个?毕竟,这样的代表无法做出有用的事情,为什么不至少发出警告呢?


4)沉默C#中的装箱和拆箱似乎更像是一个诅咒而不是帮助。

装箱的价值类型太容易了,最终只能调用

堆上的盒装副本。


最后,我正在寻找关于如何实现上述

代码试图做的建议。基本上,我需要做的是将一个已经实例化的结构分配给

的成员,但不知道结构的类型。

也就是说,我想,至少在精神上,能够通过指向结构的指针分配给结构成员



(这个问题出现在从电线上解编数据的背景下,对于

各种正当理由,我必须分配给已经实例化的

结构的成员,而不是在我拥有其所有成员值后实例化结构。)


我尝试使用指针和不安全的代码,但这只适用于非托管的类型。

但是,结构可能包含托管成员,在这种情况下我没有

更长时间创建指向结构的指针,所以这也不起作用。


任何其他人的想法吗?


谢谢,


Michi。

Below is a bit of code that creates a delegate.
The delegate invokes a member function of a struct.
The code compiles, but has surprising behavior:

using System;

namespace ConsoleApplication1
{
public struct SimpleStruct
{
public int i;

public void assignToI(int x)
{
Console.WriteLine("Assigning i: " + x);
i = x;
Console.WriteLine("i = " + x);
}
}

class Class1
{
public delegate void Assigner(int s);

private static void callDelegate(Assigner a, int i)
{
a(i);
}

static void Main(string[] args)
{
SimpleStruct s = new SimpleStruct();
s.assignToI(1); // Works as expected, assigns 1 to s.i
System.Console.WriteLine("s.i after calling assignToI = " + s.i);

// Create a delegate that calls assignToI()
Assigner assign_to_i = new Assigner(s.assignToI);

// Call helper function, passing delegate and new value for s.i
callDelegate(assign_to_i, 99);

System.Console.WriteLine("s.i after calling delegate = " + s.i);
// Assignment is lost, s.i still contains 1!!!
}
}
}

When run, this code prints:

$ ./ConsoleApplication1.exe
Assigning i: 1
i = 1
s.i after calling assignToI = 1
Assigning i: 99
i = 99
s.i after calling delegate = 1

Note that the direct call s.assignToI() works as expected:
after the call, the structure member has new value.

However, the call via the delagate does not work as expected:
the value that is assigned is lost, and the structure member
has the old value.

Now, I realize what is going on here. The delegate constructor
expects an argument of type object. In other words, the expression

new Assigner(s.assignToI)

is internally converted to something like

new Delegate(s, "assignToI")

So, the struct is silently boxed and, when the delegate runs,
what it assigns to is a temporary copy of the struct on the heap,
instead of assigning to the real struct.

Several thoughts here:

1) I find this surprising. At no point in my code have I passed the
structure as a parameter, so I don''t expect this behavior. (Yes,
I know that the struct ends up being boxed, but that is not manifest
anywhere in the code.)

2) I believe that the behavior is wrong. (Yes, I understand *why* it
works the way it does, but that doesn''t necessarily make the behavior
right.) Delegates are the equivalent of C++ member function pointers.
If I create a delegate and pass a method of a struct, I expect the
delegate to call the method on the struct instance I specified, not
some temporary copy.

3) Even if we accept that the behavior is correct, then why does the compiler
allow me to write this? After all, there is no way that such a delegate would
ever do something useful, so why not at least emit a warning?

4) The silent boxing and unboxing in C# seems to be more of a curse than helpful.
It is too easy to have a value type boxed, only to end up with invocations
made to a boxed copy on the heap.

Finally, I''m looking for suggestions as to how I can achieve what the above
code is trying to do. Basically, what I need to do is assign to a member of
an already instantiated structure, but without knowing the type of the structure.
That is, I want to, at least in spirit, be able to assign to a structure member
via a pointer to the structure.
(This issue arises in the context of unmarshaling data from the wire and, for
various legitimate reasons, I have to assign to a member of an already instatiated
structure, instead of instantiating the structure after I have all its member values.)

I tried using pointers and unsafe code, but that only works for types that are unmanaged.
However, the structure may contain managed members, in which case I can no
longer create a pointer to the struct, so this doesn''t work either.

Any other ideas anyone?

Thanks,

Michi.

推荐答案

./ ConsoleA pplication1.exe

分配i:1

i = 1

si调用assignToI = 1

分配i: 99

i = 99

si调用delegate后= 1


注意直接调用s.assignToI()按预期工作:电话结束后
,结构成员有新价值。


但是,通过delagate的电话无法按预期工作:

分配的值丢失,结构成员

具有旧值。


现在,我意识到这里发生了什么。委托构造函数

需要一个类型为object的参数。换句话说,表达


新的Assigner(s.assignToI)


内部转换为类似
的内容>
新代表(s,assignToI)


因此,结构是静默装箱的,当委托运行时,

是什么它指定的是堆上结构的临时副本,

而不是分配给真正的结构。


这里有几个想法:


1)我觉得这很令人惊讶。在我的代码中,我没有通过

结构作为参数,所以我不期望这种行为。 (是的,

我知道结构最终被装箱了,但是代码中的任何地方都没有显示

。)


2)我认为这种行为是错误的。 (是的,我理解*为什么*它

按照它的方式工作,但这并不一定使行为

正确。)代表相当于C ++成员函数指针。

如果我创建一个委托并传递一个struct的方法,我希望

委托在我指定的struct实例上调用该方法,而不是

一些临时副本。


3)即使我们接受行为是正确的,那么为什么编译器

允许我写这个?毕竟,这样的代表无法做出有用的事情,为什么不至少发出警告呢?


4)沉默C#中的装箱和拆箱似乎更像是一个诅咒而不是帮助。

装箱的价值类型太容易了,最终只能调用

堆上的盒装副本。


最后,我正在寻找关于如何实现上述

代码试图做的建议。基本上,我需要做的是将一个已经实例化的结构分配给

的成员,但不知道结构的类型。

也就是说,我想,至少在精神上,能够通过指向结构的指针分配给结构成员



(这个问题出现在从电线上解编数据的背景下,对于

各种正当理由,我必须分配给已经实例化的

结构的成员,而不是在我拥有其所有成员值后实例化结构。)


我尝试使用指针和不安全的代码,但这只适用于非托管的类型。

但是,结构可能包含托管成员,在这种情况下我没有

更长时间创建指向结构的指针,所以这也不起作用。


任何其他人的想法吗?


谢谢,


Michi。
./ConsoleApplication1.exe
Assigning i: 1
i = 1
s.i after calling assignToI = 1
Assigning i: 99
i = 99
s.i after calling delegate = 1

Note that the direct call s.assignToI() works as expected:
after the call, the structure member has new value.

However, the call via the delagate does not work as expected:
the value that is assigned is lost, and the structure member
has the old value.

Now, I realize what is going on here. The delegate constructor
expects an argument of type object. In other words, the expression

new Assigner(s.assignToI)

is internally converted to something like

new Delegate(s, "assignToI")

So, the struct is silently boxed and, when the delegate runs,
what it assigns to is a temporary copy of the struct on the heap,
instead of assigning to the real struct.

Several thoughts here:

1) I find this surprising. At no point in my code have I passed the
structure as a parameter, so I don''t expect this behavior. (Yes,
I know that the struct ends up being boxed, but that is not manifest
anywhere in the code.)

2) I believe that the behavior is wrong. (Yes, I understand *why* it
works the way it does, but that doesn''t necessarily make the behavior
right.) Delegates are the equivalent of C++ member function pointers.
If I create a delegate and pass a method of a struct, I expect the
delegate to call the method on the struct instance I specified, not
some temporary copy.

3) Even if we accept that the behavior is correct, then why does the compiler
allow me to write this? After all, there is no way that such a delegate would
ever do something useful, so why not at least emit a warning?

4) The silent boxing and unboxing in C# seems to be more of a curse than helpful.
It is too easy to have a value type boxed, only to end up with invocations
made to a boxed copy on the heap.

Finally, I''m looking for suggestions as to how I can achieve what the above
code is trying to do. Basically, what I need to do is assign to a member of
an already instantiated structure, but without knowing the type of the structure.
That is, I want to, at least in spirit, be able to assign to a structure member
via a pointer to the structure.
(This issue arises in the context of unmarshaling data from the wire and, for
various legitimate reasons, I have to assign to a member of an already instatiated
structure, instead of instantiating the structure after I have all its member values.)

I tried using pointers and unsafe code, but that only works for types that are unmanaged.
However, the structure may contain managed members, in which case I can no
longer create a pointer to the struct, so this doesn''t work either.

Any other ideas anyone?

Thanks,

Michi.


如果你让SimpleStruct成为一个类,它会按预期工作。问题是

结构是值类型,而不是参考。


在这里阅读更多:
http://msdn.microsoft。 com / library / de ... arpspec_11.asp


Pete


" Michi Henning" < MI *** @ zeroc.com>在消息中写道

新闻:OU ****************** @ TK2MSFTNGP09.phx.gbl ...
If you make SimpleStruct a class, it will work as expected. The problem is
that a struct is a value type, not a reference.

Read more here:
http://msdn.microsoft.com/library/de...arpspec_11.asp

Pete

"Michi Henning" <mi***@zeroc.com> wrote in message
news:OU******************@TK2MSFTNGP09.phx.gbl...
下面是一个创建委托的代码。
委托调用结构的成员函数。
代码编译,但有令人惊讶的行为:

使用系统; 公共结构SimpleStruct
公共int i;

public void assignToI(int x)
{
Console.WriteLine(" Assigning i:" + x);
i = x;
Console.WriteLine(" i =" + x); {
公共委托void Assigner(int s);

private static void callDelegate(Assigner a,int i)
{
a(i);
}

static void Main(string [] args)
{
SimpleStruct s = new Simp leStruct();
s.assignToI(1); //按预期工作,将1分配给Si
System.Console.WriteLine(在调用assignToI =" +
si后调用si);

//创建代理调用assignToI()
Assigner assign_to_i = new Assigner(s.assignToI);

//调用辅助函数,传递委托和新值
si
callDelegate (assign_to_i,99);

System.Console.WriteLine(在调用delegate =" +
si之后的si);
//赋值丢失,si仍然包含1 !!!
}
}

运行时,此代码打印:

Below is a bit of code that creates a delegate.
The delegate invokes a member function of a struct.
The code compiles, but has surprising behavior:

using System;

namespace ConsoleApplication1
{
public struct SimpleStruct
{
public int i;

public void assignToI(int x)
{
Console.WriteLine("Assigning i: " + x);
i = x;
Console.WriteLine("i = " + x);
}
}

class Class1
{
public delegate void Assigner(int s);

private static void callDelegate(Assigner a, int i)
{
a(i);
}

static void Main(string[] args)
{
SimpleStruct s = new SimpleStruct();
s.assignToI(1); // Works as expected, assigns 1 to s.i
System.Console.WriteLine("s.i after calling assignToI = " +
s.i);

// Create a delegate that calls assignToI()
Assigner assign_to_i = new Assigner(s.assignToI);

// Call helper function, passing delegate and new value for
s.i
callDelegate(assign_to_i, 99);

System.Console.WriteLine("s.i after calling delegate = " +
s.i);
// Assignment is lost, s.i still contains 1!!!
}
}
}

When run, this code prints:


./ ConsoleApplication1.exe
分配i:1
i = 1
si调用assignToI = 1
分配i:99
i = 99
请注意直接调用s.assignToI()按预期工作:
调用后,结构成员有新的值e。

然而,通过delagate的调用不能按预期工作:
分配的值丢失,结构成员
具有旧值。 />
现在,我意识到这里发生了什么。委托构造函数
期望一个类型为object的参数。换句话说,表达

新的Assigner(s.assignToI)

内部转换为类似

新代表(s," assignToI")

所以,结构是静默装箱的,当委托运行时,
它所分配的是堆上结构的临时副本,而不是分配到真正的结构。

这里有几个想法:

1)我觉得这很令人惊讶。在我的代码中,我没有将
结构作为参数传递,所以我不期望这种行为。 (是的,
我知道结构最终会被装箱,但在代码中的任何地方都没有显示。)

2)我认为这种行为是错误的。 (是的,我理解*为什么*它按照它的方式工作,但这并不一定使行为正确。)委托相当于C ++成员函数指针。
如果我创建一个委托并传递一个struct的方法,我希望
委托在我指定的struct实例上调用该方法,而不是一些临时副本。

3 )即使我们接受行为是正确的,那么为什么
编译器允许我写这个?毕竟,这样的代表无法做出有用的事情,为什么不至少发出警告呢?

4)沉默的拳击和拆箱C#似乎更像是一个诅咒而不是
帮助。
有一个盒子的值类型太容易了,结果只是对盒装副本进行了
调用。堆。

最后,我正在寻找关于如何实现上面的代码试图做的建议。基本上,我需要做的是分配一个已经实例化的结构的成员,但不知道
结构的类型。
也就是说,我想,至少在精神上,能够通过指向结构的指针分配给一个结构
成员。
(这个问题出现在从电线解编数据的背景下,
为了各种合理的原因,我必须分配给已经建立的
结构的成员,而不是在我拥有所有成员值之后实例化结构。)

我尝试使用指针和不安全的代码,但这只适用于
不受管理的类型。
然而,结构可能包含托管成员,在这种情况下我不能
更长时间创建指向结构的指针,所以这也不起作用。

任何其他人的想法吗?

谢谢,

Michi。
./ConsoleApplication1.exe
Assigning i: 1
i = 1
s.i after calling assignToI = 1
Assigning i: 99
i = 99
s.i after calling delegate = 1

Note that the direct call s.assignToI() works as expected:
after the call, the structure member has new value.

However, the call via the delagate does not work as expected:
the value that is assigned is lost, and the structure member
has the old value.

Now, I realize what is going on here. The delegate constructor
expects an argument of type object. In other words, the expression

new Assigner(s.assignToI)

is internally converted to something like

new Delegate(s, "assignToI")

So, the struct is silently boxed and, when the delegate runs,
what it assigns to is a temporary copy of the struct on the heap,
instead of assigning to the real struct.

Several thoughts here:

1) I find this surprising. At no point in my code have I passed the
structure as a parameter, so I don''t expect this behavior. (Yes,
I know that the struct ends up being boxed, but that is not manifest
anywhere in the code.)

2) I believe that the behavior is wrong. (Yes, I understand *why* it
works the way it does, but that doesn''t necessarily make the behavior
right.) Delegates are the equivalent of C++ member function pointers.
If I create a delegate and pass a method of a struct, I expect the
delegate to call the method on the struct instance I specified, not
some temporary copy.

3) Even if we accept that the behavior is correct, then why does the
compiler
allow me to write this? After all, there is no way that such a delegate
would
ever do something useful, so why not at least emit a warning?

4) The silent boxing and unboxing in C# seems to be more of a curse than
helpful.
It is too easy to have a value type boxed, only to end up with
invocations
made to a boxed copy on the heap.

Finally, I''m looking for suggestions as to how I can achieve what the
above
code is trying to do. Basically, what I need to do is assign to a member
of
an already instantiated structure, but without knowing the type of the
structure.
That is, I want to, at least in spirit, be able to assign to a structure
member
via a pointer to the structure.
(This issue arises in the context of unmarshaling data from the wire and,
for
various legitimate reasons, I have to assign to a member of an already
instatiated
structure, instead of instantiating the structure after I have all its
member values.)

I tried using pointers and unsafe code, but that only works for types that
are unmanaged.
However, the structure may contain managed members, in which case I can no
longer create a pointer to the struct, so this doesn''t work either.

Any other ideas anyone?

Thanks,

Michi.



这篇关于结构和代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆