通用代理类型解释(示例) [英] Generic Delegate Types explained (example)

查看:150
本文介绍了通用代理类型解释(示例)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个显示通用委托类型的好例子。阅读这个

,您将对如何使用这些

类型有一个很好的理解。您可能会说通用代理

类型表达式在恰当的位置和名称很好的方法的组合意味着

我们几乎可以大声读出代码并理解它甚至没有

思考。


请注意,由于涉及''拳击''和''拆箱''(我认为),你

如果你传递一个值类型,你不会得到你所期望的(参见输出

标记为//不是你想要的 - baad!)


要解决这个问题,你必须创建一个委托参数

,它接受一个对象(引用类型)。然后它就可以了。


但是,只是为了表明''ref''是如何工作的,当名为

的泛型方法通过引用而不是通过对象传递时(每当''new''在方法中使用
时,必须重命名代表(从Transformer改为

''Uransformer'')。不知道为什么会这样,但是这就是它b / b
的方式。


最后,请注意如何更改对象是否可以如果您传递的是物品,则按价值传递

或参考。这甚至适用于

字符串。请注意,在通用

委托的两个版本中都更改了字符串,Transform2和Transform3。


如何制作''通用委托类型''?仔细阅读了这个

示例(这是对原始委托类型的一个非常原始的

示例的修改,取自C#3.0的第108页

Nutshell,它形成了第一个输出,涉及平方值

类型),我确信通用委托类型是

灾难的补充,因为基本上他们做的远离强烈的打字(无论是什么

这意味着,但我的心目中有一个理解)。


我能看到的唯一优势是只是一种光滑的方式宣布一个

代表公共代表T Transformer< T(T arg); "然后

允许你编写遵循这个模板的方法/函数来获取
a类型T并返回一个类型T(无论T是int,double,或者

甚至是一个对象),尽管方法/功能从根本上说是不同的b $ b。然后可以使用下面的约定

调用这些方法。很重要。灾难的消息。


大笔交易和灾难的消息与lambda表达并没有什么区别

和匿名代表 (这两个主题我都不熟悉)。

如果有人可以将泛型代表类型与这些

两个主题相关联,那么我们将不胜感激。


RL


(c)2008,保留所有权利,''艺术许可'',且无效

禁止。仅供skoorly使用。无论这意味着什么,作者的精神权利都被保留了。 Copyleft免费使用,无需
归属地。<​​br />

//输出


1X! 2X! 3X! 1SQ! 4SQ! 9Sq! 1CB! 64Cb! 729Cb! //注意这可以作为

预期,因为9x9x9 = 729,并且每个数组元素都在按预期更改




现在值[X]:2 //不是你想要的 - baad!

现在价值[Square]:2 //不是你想要的 - baad!

value现在[Cube]:2 //不是你想要的 - baad!

____________


现在价值[X]:3 //不是你想要的 - baad!

现在价值[Square]:3 //不是你想要的 - baad!

现在价值[Cube]:3 //不是你想要的 - baad!

_____UtilSquarer______

现在
值[UtilSquarer]:9 //现在工作正常

字符串值[UtilSquarer]:再见!

_____UtilStringChanger______


字符串值[UtilStringChanger]:BAA_is_a_goodBuy! //字符串

更改正确(2种方式中的1种更改字符串;请参阅下面的参考资料

版本)

__UtilStringChanger2AndMoreStaticVer__


string的值,int是[UtilStringChanger2AndMoreStaticVersion]:

anotherStrin

gHere! ,10001

按任意键继续。 。 。

/////////////////////


使用系统;

使用System.Collections.Generic;

使用System.Text;


命名空间p108DelegatesCSNutshell

{

公共代表T Transformer< T(T arg);

公共代表T Uransformer< T(ref T arg); //轻微的名称更改
'ref''版本需要
,否则不会编译

class program

{

static void Main(string [] args)

{

int [] values = new int [] {1,2,3};

int value = 2;

Util myUtil = new Util();


Util.Transform1(values,ReturnX); //动态挂钩

ReturnX

foreach(int i in values)

{

Console.Write(i +X!;;

}


Util.Transform1(values,Square); //动态挂钩方块

foreach(int i in values)

{

Console.Write(i +" Sq!") ;

}


Util.Transform1(values,myUtil.Cube); //动态挂钩

cube

foreach(int i in values)

{

Console.Write(i +Cb!;

}


Console.WriteLine(" \ n");

myUtil.Transform2(value,ReturnX);

Console.WriteLine(" value now [X]:{0}",value);

myUtil.Transform2( value,Square);

Console.WriteLine(" value now [Square]:{0}",value);

myUtil.Transform2(value,myUtil。 Cube);

Console.WriteLine(" value now [Cube]:{0}",value);


Console.WriteLine(" ____________ \ n");


myUtil.Transform2(myUtil.j,ReturnX);

Console.WriteLine(" value now [X]: {0}",myUtil.j);

myUtil.Transform2(myUtil.j,Square);

Console.WriteLine(" value now [Square]: {0}",myUtil.j);

myUtil.Transform2(value,myUtil.Cube);

Console.WriteLine(" value now [Cube]: {0},我的Util.j);


Console.WriteLine(" _____ UtilSquarer______ \ n");


myUtil.Transform2(myUtil,myUtil。 UtilSquarer);

Console.WriteLine(" value now [UtilSquarer]:{0}",

myUtil.j);

Console.WriteLine(" string [utilSquarer]的值:{0}",

myUtil.s);


Console.WriteLine(" _____UtilStringChanger______ \ n");


myUtil.Transform3(ref myUtil,myUtil.UtilStringChanger);

Console.WriteLine(" string of value [UtilStringChanger] ]:

{0}",myUtil.s);


Console.WriteLine(" __ UtilStringChanger2AndMoreStat icVer__

\\ \\ n");

myUtil.Transform3(ref myUtil,

UtilStringChanger2AndMoreStaticVersion);

Console.WriteLine(" string,int的值)是

[UtilStringChanger2AndMoreStaticVersion]:{0},{1}",myUtil.s,

myUtil.j);

}


static int ReturnX(int x)

{

返回x;

}

static int Square(int x)

{

返回x * x;

}

静态Util UtilStringChanger2AndMoreStaticVersion(ref Util U)

{

U = new Util();

Us =" anotherStringHere !" ;;

Uj = 10001;

返回U;

}


} < br $>
}

/////////////////////


使用系统;

使用System.Collections.Generic;

使用System.Text;


命名空间p108DelegatesCSNutshell

{

class Util

{

public int j;

public string s;

public Util()

{

s =" hi";

j = 3;

}


public static void Transform1< T>(T [] values,Transformer< Tt)

{

for(int i = 0;我< values.Length; i ++)

values [i] = t(values [i]);

}

public int Cube(int x){return x * x * x; }


公共Util UtilSquarer(Util U)

{

Uj = Uj * Uj;

Us =再见!;


// U = new Util(); //接下来3行不会在这里工作,因为参考

没有通过

// Uj = Uj * Uj;

//我们=" NoGo"


返回U;


}


public Util UtilStringChanger( ref Util U)

{

U = new Util();

Us =" BAA_is_a_goodBuy!";

返回U;

}

public void Transform2< T>(T值,Transformer< Tt)

{value = t(值); }


public void Transform3< T>(ref T值,Uransformer< Tt)

{

value = t(ref价值);

}


}

}

解决方案

raylopez99写道:


我确信通用委托类型是

灾难的收据,因为基本上他们不再使用强烈的打字(无论

这意味着什么,但我的心目中有一个理解)。



我断言这篇文章表明你不知道什么是强烈的

打字手段。事实上,如果你知道强大的打字意味着什么,那么你可以通过向我展示类型违规来说服我。


继续。告诉我。


- 巴里


-
http://barrkel.blogspot.com/


好奇,这只是不是这类帖子的正确论坛。尝试

类似codeproject或博客。但要理解它:


你的帖子不仅有事实和遗漏的错误(并且

最多也不清楚),你反复说过你不明白

某些东西,但不知何故觉得有资格在

同时对它们发表评论。这篇文章对任何人都没有帮助 - 虽然没有

怀疑另一个很长但最终没有结果的链条会随之而来。来吧

开启,请停止使用拖钓/火焰术,这样我们实际上可以确保这个论坛有用了。


Marc


raylopez99写道:


这是一个显示通用委托类型的好例子。阅读这个

,您将对如何使用这些

类型有一个很好的理解。



不是真的,因为它们没有以合理的方式使用。


你可能会说通用代表

类型表达式的组合在恰当的位置和一个命名良好的方法意味着

我们几乎可以大声读出代码并且无法理解它

思考。


请注意,因为''拳击''和''取消装箱''涉及(我认为),


不,这不正确。没有拳击正在进行,除非当然你指定了对象和对象。作为泛型类型,并将值类型发送到

方法。


you

don''如果你传递一个值类型,你会得到你期望的东西(参见输出

标记为//不是你想要的东西 - baad!)



如果这不是你所期望的,你真的不明白如何将参数

发送给方法。


你正在传递价值的副本。更改副本不会改变原始的
。每次调用方法时都会以相同的方式运行,它是

使用泛型或使用委托时没什么特别的。


要解决此问题,您必须创建一个委托参数

,它接受一个对象(引用类型)。然后它工作。



不,这没什么区别。


除非你特别声明通用类型必须是一个

值类型,它总是一个引用类型。


但是,引用仍然是按值发送的,这意味着它是一个副本

发送给方法的引用。更改

引用的副本仍然不会更改原始引用,因此即使您发送引用类型,也不能使用
替换该对象方法。


但是,只是为了表明''ref''如何工作,当名为

的泛型方法通过引用传递而不是按对象(每当''新''是

在方法中使用时需要)



通过引用传递参数不是一回事将

引用类型作为参数传递。


代表必须重命名(从Transformer到

''Uransformer'')。不知道为什么会这样,但这就是它b / b
的方式。



这是因为你不能有两个具有相同签名的方法。

ref关键字不是签名的一部分(至少不在此上下文中)。


最后,请注意如何更改如果您传递的是对象,则对象是否按值传递

或引用。



不,这不正确。您可能可以更改

对象的内容,但如果您不通过

引用发送它,则无法替换该对象本身。 br />


即使对于

字符串也是如此。请注意,在通用

委托的两个版本中都更改了字符串,Transform2和Transform3。



不,这不正确。字符串是不可变的,这意味着你不能改变现有字符串对象的内容。要更改

a字符串的值,您必须将其替换为新的字符串实例,除非您通过引用该方法发送字符串,否则您不能执行


如何制作''通用委托类型''?仔细阅读了这个

示例(这是对原始委托类型的一个非常原始的

示例的修改,取自C#3.0的第108页

Nutshell,它形成了第一个输出,涉及平方值

类型),我确信通用委托类型是

灾难的补充,因为基本上他们做的远离强烈的打字(无论

这意味着什么,但我的脑海中有一种理解)。



不,这不正确。通用委托类型仍然非常强大。

键入。仅仅因为该方法中未指定类型并不意味着它不是强类型的。类型仍然必须在编译时知道。

时间。


我能看到的唯一优势就是宣布一个光滑的方式br />
delegate"公共代表T Transformer< T(T arg); "然后

允许你编写遵循这个模板的方法/函数来获取
a类型T并返回一个类型T(无论T是int,double,或者

甚至是一个对象),尽管方法/功能从根本上说是不同的b $ b。然后可以使用下面的约定

调用这些方法。很重要。灾难的消息。



真正的优势实际上不是你可以使用

委托调用的方法,但你可以编写调用方法的方法委托。


大笔交易和灾难收集与lambda表达并没有什么区别

和匿名委托 (这两个主题我都不熟悉)。

如果有人可以将泛型代表类型与这些两个主题相关联的方式联系起来,我们将不胜感激。



Lambda表达式只是匿名方法的语法糖。


术语匿名委托并不是什么意思。就像

将文字值称为匿名变量一样。这个术语是

匿名方法,并且作为一个匿名方法没有名字,

只能使用它的方法是通过委托来引用它。 br />

匿名方法只是一种编写

代码内联方法的方法,然后(例如)可以将其分配给委托。示例:


//为委托分配命名方法:

Transformer< inttrans1 = ReturnX;

//分配一个委托人的匿名方法:

Transformer< inttrans2 = delegate(int x){return x; };


>

RL


(c)2008,保留所有权利,通过''艺术许可''和无效的地方

禁止。仅供skoorly使用。无论这意味着什么,作者的精神权利都被保留了。 Copyleft免费使用,无需
归属地。<​​br />

//输出


1X! 2X! 3X! 1SQ! 4SQ! 9Sq! 1CB! 64Cb! 729Cb! //注意这可以作为

预期,因为9x9x9 = 729,并且每个数组元素都在按预期更改




现在值[X]:2 //不是你想要的 - baad!

现在价值[Square]:2 //不是你想要的 - baad!

value现在[Cube]:2 //不是你想要的 - baad!

____________


现在价值[X]:3 //不是你想要的 - baad!

现在价值[Square]:3 //不是你想要的 - baad!

现在价值[Cube]:3 //不是你想要的 - baad!

_____UtilSquarer______

现在
值[UtilSquarer]:9 //现在工作正常

字符串值[UtilSquarer]:再见!

_____UtilStringChanger______


字符串值[UtilStringChanger]:BAA_is_a_goodBuy! //字符串

更改正确(2种方式中的1种更改字符串;请参阅下面的参考资料

版本)

__UtilStringChanger2AndMoreStaticVer__


string的值,int是[UtilStringChanger2AndMoreStaticVersion]:

anotherStrin

gHere! ,10001

按任意键继续。 。 。

/////////////////////


使用系统;

使用System.Collections.Generic;

使用System.Text;


命名空间p108DelegatesCSNutshell

{

公共代表T Transformer< T(T arg);

公共代表T Uransformer< T(ref T arg); //轻微的名称更改
'ref''版本需要
,否则不会编译


class program

{

static void Main(string [] args)

{

int [] values = new int [] {1,2,3 };

int value = 2;

Util myUtil = new Util();


Util.Transform1(values,ReturnX ); //动态挂钩

ReturnX



由于该方法是通用的,您需要在调用时指定类型:


Util.Transform1< int>(values,ReturnX);


foreach(int i in values)

{

Console.Write(i +" X!");

}


Util.Transform1(值,Square); //动态挂钩方块

foreach(int i in values)

{

Console.Write(i +" Sq!") ;

}


Util.Transform1(values,myUtil.Cube); //动态挂钩

立方体



Cube方法应该是静态的(见下文),所以你应该指定

委托为Util.Cube。


当您在变量中发送值的副本时,方法只需更改
复制,然后把它扔掉。


foreach(int i in values)

{

Console.Write (i +Cb!);

}


Console.WriteLine(" \ n");

myUtil.Transform2(value,ReturnX);



也是一种通用方法,因此您必须指定类型。 Transform2

方法应该是静态的(见下文),所以你应该使用类名来

调用它:


Util.Transform2< int>(value,ReturnX);


当您在变量中发送值的副本时,方法只需更改
复制,然后把它扔掉。


Console.WriteLine(" value now [X]:{0}",value);

myUtil.Transform2(value,Square);

Console.WriteLine(" value now [Square]:{0}",value);

myUtil。 Transform2(value,myUtil.Cube);

Console.WriteLine(" value now [Cube]:{0}",value);


Console.WriteLine(" ____________ \ n");


myUtil.Transform2(myUtil.j,ReturnX);



发送对象成员的副本与发送

本地变量的副本相同。该方法仍然只能更改副本。


Console.WriteLine(" value now [X]:{0}",myUtil.j);

myUtil.Transform2(myUtil.j,Square);

Console.WriteLine(" value now [Square]:{0}",myUtil.j);

myUtil.Transform2(value,myUtil.Cube);

Console.WriteLine(" value now [Cube]:{0}",myUtil.j);


Console.WriteLine(" _____ UtilSquarer______ \ n");


myUtil.Transform2(myUtil,myUtil.UtilSquarer);

Console.WriteLine(" value now [UtilSquarer]:{0}",

myUtil.j);

Console.WriteLine(&value; value of string [UtilSquarer]:{0}",

myUtil.s);


Console.WriteLine(" _____ UtilStringChanger______ \ n");


myUtil.Transform3(ref myUt il,myUtil.UtilStringChanger);

Console.WriteLine(" string [UtilStringChanger]的值:

{0}",myUtil.s);



Transform3方法应该是静态的(见下文),因此你应该指定

类名而不是实例名。


由于方法是通用的,你必须在调用它时指定类型。


UtilStringChanger应该是静态的(见下文),所以你应该指定

类名而不是实例名。


>

Console.WriteLine(" ; __ UtilStringChanger2AndMoreStat icVer__

\ n");

myUtil.Transform3(ref myUtil,

UtilStringChanger2AndMoreStaticVersion);

Console.WriteLine(" string,int的值是

[UtilStringChanger2AndMoreStaticVersion]:{0},{1}",myUtil.s,

myUtil.j );


}


static int ReturnX(int x)

{

返回x;

}


static int Square(int x)

{

返回x * x;

}


静态Util UtilStringChanger2AndMoreStaticVersion(ref Util U)

{

U = new Util();



因为你立即扔掉论证中的任何内容,

你应该使用out而不是ref。


Us =" anotherStringHere!" ;;

Uj = 10001;

返回U;



改变参数并将其返回是毫无意义的。


}


}

}

/////////////////////


使用System;

使用System.Collections.Generic;

使用System.Text;


namespace p108DelegatesCSNutshell

{

class Util

{

public int j;

public string s;

public Util()

{

s =" hi";

j = 3;

}


public static void Transform1< T>(T [] values,Transformer< Tt)

{

for(int i = 0; i< values.Length; i ++)

values [i] = t(values [i]);

}

public int Cube(int x){return x * x * x; }



Cube方法在Util实例中没有使用任何东西,所以它应该是

是静态的。
< blockquote class =post_quotes>
public Util UtilSquarer(Util U)

{

Uj = Uj * Uj;

Us =再见!;


// U =新的Util(); //接下来3行不会在这里工作,因为参考

没有通过

// Uj = Uj * Uj;

//我们=NoGo;


返回U;



改变参数并将其返回是毫无意义的。


>

}


public Util UtilStringChanger(ref Util U)



UtilStringChanger方法不会在Util实例中使用任何东西,

所以它应该是静态的。


{

U = new Util ();

Us =" BAA_is_a_goodBuy!" ;;

返回U;



改变参数并将其返回是毫无意义的。


}


public void Transform2< T>(T值,Transformer< Tt)



Transform2方法没有使用任何东西Util实例,所以它b / b应该是静态的。


{value = t(value); }



将委托调用的返回值赋值给值变量

不起任何作用。由于参数只包含

值的副本(无论该值是值类型值还是对

引用类型的引用),它从未使用过分配后。


>

public void Transform3< T>(ref T value,Uransformer< Tt)



Transform3方法在Util实例中没有使用任何东西,因此它应该是静态的。


{

value = t(ref value);



通过引用

委托调用发送值变量并为其分配返回值是没有意义的。无论方法

分配给参数,它都会被返回值覆盖。


}


}

}



-

G?跑Andersson

_____
http://www.guffa.com

Here is a good example that shows generic delegate types. Read this
through and you''ll have an excellent understanding of how to use these
types. You might say that the combination of the generic delegate
type expression in just the right place and a well-named method means
we can almost read the code out loud and understand it without even
thinking.

Note that since ''boxing'' and ''unboxing'' is involved (I think), you
don''t get what you expect if you pass a value type (see the output
labeled "//not what you want - baad!")

To get around this problem, you have to create a delegate parameter
that accepts an object (reference type). Then it works.

However, just to show how ''ref'' works, when the generic method called
passes by reference rather than by object (required whenever ''new'' is
used in a method) the delegate had to be renamed (from Transformer to
''Uransformer''). Don''t know why this is the case but that''s the way it
is.

Finally, note how you can change an object whether your pass by value
or by reference, if you are passing the object. This holds even for
strings. Note the strings are changed in both versions of the generic
delegates, "Transform2" and "Transform3".

What to make of ''generic delegate types''? After going through this
example carefully (which was a modification of a extremely primitive
example of generic delegate types taken from p. 108 of the C# 3.0
Nutshell, which formed the first output, involving squaring a value
type), I am convinced generic delegate types are a receipe for
disaster, since essentially they do away with strong typing (whatever
that means, but I have an understanding in my mind''s eye).

The only advantage I can see is just a slick way of declaring a
delegate " public delegate T Transformer<T(T arg); " that will then
allow you to write methods/functions that obey this template of taking
a type T and returning a type T (whether the T is an int, a double, or
even an object), though the methods/functions are radically
different. These methods can then be called using the convention
below. Big deal. A receipe for disaster.

Big deal and a receipe for disaster is not unlike "lambda expressions"
and "anonymous delegates" (both topics I''m not that familiar with).
If anybody can relate how generic delegate types correlate with these
two topics it would be appreciated.

RL

(c) 2008, all rights reserved, by ''artistic license'' and void where
prohibited. For skolarly use only. The moral rights of the author are
preserved, whatever that means. Copyleft and free to use without
attribution.

// output

1X! 2X! 3X! 1Sq! 4Sq! 9Sq! 1Cb! 64Cb! 729Cb! //note this works as
expected, since 9x9x9 = 729, and each array element is being changed
as expected.

value now [X]: 2 //not what you want - baad!
value now [Square]: 2 //not what you want - baad!
value now [Cube]: 2 //not what you want - baad!
____________

value now [X]: 3 //not what you want - baad!
value now [Square]: 3 //not what you want - baad!
value now [Cube]: 3 //not what you want - baad!
_____UtilSquarer______

value now [UtilSquarer]: 9 //now works fine
value of string [UtilSquarer]: goodbye!
_____UtilStringChanger______

value of string [UtilStringChanger]: BAA_is_a_goodBuy! //string
changed properly (1 of 2 ways to change string; see below for ref
version)
__UtilStringChanger2AndMoreStaticVer__

values of string, int are [UtilStringChanger2AndMoreStaticVersion]:
anotherStrin
gHere! , 10001
Press any key to continue . . .
/////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace p108DelegatesCSNutshell
{
public delegate T Transformer<T(T arg);
public delegate T Uransformer<T(ref T arg); //slight name change
needed for ''ref'' version, otherwise won''t compile
class Program
{
static void Main(string[] args)
{
int[] values = new int[] { 1, 2, 3 };
int value = 2;
Util myUtil = new Util();

Util.Transform1(values, ReturnX); //dynamically hook
ReturnX
foreach (int i in values)
{
Console.Write(i + "X! ");
}

Util.Transform1(values, Square); //dynamically hook square
foreach (int i in values)
{
Console.Write(i + "Sq! ");
}

Util.Transform1(values, myUtil.Cube); //dynamically hook
cube
foreach (int i in values)
{
Console.Write(i + "Cb! ");
}

Console.WriteLine("\n");
myUtil.Transform2(value, ReturnX);
Console.WriteLine("value now [X]: {0}", value);
myUtil.Transform2(value, Square);
Console.WriteLine("value now [Square]: {0}", value);
myUtil.Transform2(value, myUtil.Cube);
Console.WriteLine("value now [Cube]: {0}", value);

Console.WriteLine("____________ \n");

myUtil.Transform2(myUtil.j, ReturnX);
Console.WriteLine("value now [X]: {0}", myUtil.j);
myUtil.Transform2(myUtil.j, Square);
Console.WriteLine("value now [Square]: {0}", myUtil.j);
myUtil.Transform2(value, myUtil.Cube);
Console.WriteLine("value now [Cube]: {0}", myUtil.j);

Console.WriteLine("_____UtilSquarer______ \n");

myUtil.Transform2(myUtil, myUtil.UtilSquarer);
Console.WriteLine("value now [UtilSquarer]: {0}",
myUtil.j);
Console.WriteLine("value of string [UtilSquarer]: {0}",
myUtil.s);

Console.WriteLine("_____UtilStringChanger______ \n");

myUtil.Transform3(ref myUtil, myUtil.UtilStringChanger);
Console.WriteLine("value of string [UtilStringChanger]:
{0}", myUtil.s);

Console.WriteLine("__UtilStringChanger2AndMoreStat icVer__
\n");
myUtil.Transform3(ref myUtil,
UtilStringChanger2AndMoreStaticVersion);
Console.WriteLine("values of string, int are
[UtilStringChanger2AndMoreStaticVersion]: {0} , {1}", myUtil.s,
myUtil.j);
}

static int ReturnX(int x)
{
return x;
}

static int Square(int x)
{
return x * x;
}

static Util UtilStringChanger2AndMoreStaticVersion(ref Util U)
{
U = new Util();
U.s = "anotherStringHere!";
U.j = 10001;
return U;
}

}
}
/////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace p108DelegatesCSNutshell
{
class Util
{
public int j;
public string s;
public Util ()
{
s = "hi";
j = 3;
}

public static void Transform1<T>(T[] values, Transformer<Tt)
{
for (int i = 0; i < values.Length; i++)
values[i] = t(values[i]);
}
public int Cube(int x) { return x * x * x; }

public Util UtilSquarer(Util U)
{
U.j = U.j * U.j;
U.s = "goodbye!";

//U = new Util(); //next 3 lines won''t work here since ref
not passed
//U.j = U.j * U.j;
//U.s = "NoGo";

return U;

}

public Util UtilStringChanger(ref Util U)
{
U = new Util();
U.s = "BAA_is_a_goodBuy!";
return U;
}
public void Transform2<T>(T value, Transformer<Tt)
{ value = t(value); }

public void Transform3<T>(ref T value, Uransformer<Tt)
{
value = t(ref value);
}

}
}

解决方案

raylopez99 wrote:

I am convinced generic delegate types are a receipe for
disaster, since essentially they do away with strong typing (whatever
that means, but I have an understanding in my mind''s eye).

I assert that this post indicates that you have no idea what "strong
typing" means. If you do, in fact, know what strong typing means, you
should be able to convince me by showing me the type violation.

Go on. Show me.

-- Barry

--
http://barrkel.blogspot.com/


Seiously, this just isn''t the right forum for this type of post. Try
something like codeproject or a blog. But to disect it:

Not only is your post full of errors both of fact and omission (and
unclear at best), you repeatedly remark that you don''t understand
certain things, but somehow feel qualified to comment on them at the
same time. This post simply isn''t helpful to anyone - although no
doubt another long but ultimately fruitless chain will follow. Come
on, please stop with the trolling / flamebaiting so we can actually
keep this forum useful.

Marc


raylopez99 wrote:

Here is a good example that shows generic delegate types. Read this
through and you''ll have an excellent understanding of how to use these
types.

Not really, as they are not used in a way that makes sense.

You might say that the combination of the generic delegate
type expression in just the right place and a well-named method means
we can almost read the code out loud and understand it without even
thinking.

Note that since ''boxing'' and ''unboxing'' is involved (I think),

No, that''s not correct. There is no boxing going on, unless of course
you specify "object" as the generic type, and send a value type to the
method.

you
don''t get what you expect if you pass a value type (see the output
labeled "//not what you want - baad!")

If that''s not what you expect, you don''t really understand how arguments
are sent to a method.

You are passing a copy of the value. Changing the copy will not change
the original. That works the same way every time you call a method, it''s
nothing that is special when using generics or when using delegates.

To get around this problem, you have to create a delegate parameter
that accepts an object (reference type). Then it works.

No, that doesn''t make any difference.

Unless you have specifically stated that the generic type has to be a
value type, it can always be a reference type.

However, a reference is still sent by value, meaning that it''s a copy of
the reference that is sent to the method. Changing the copy of the
reference still doesn''t change the original reference, so you can''t
replace the object even if you are sending a reference type to the method.

However, just to show how ''ref'' works, when the generic method called
passes by reference rather than by object (required whenever ''new'' is
used in a method)

Passing an argument by reference is not the same thing as passing a
reference type as an argument.

the delegate had to be renamed (from Transformer to
''Uransformer''). Don''t know why this is the case but that''s the way it
is.

That''s because you can''t have two methods with the same signature. The
ref keyword is not part of the signature (at least not in this context).

Finally, note how you can change an object whether your pass by value
or by reference, if you are passing the object.

No, that is not correct. You may be able to change the contents of an
object, but you can''t replace the object itself if you don''t send it by
reference.

This holds even for
strings. Note the strings are changed in both versions of the generic
delegates, "Transform2" and "Transform3".

No, that is not correct. Strings are immutable, meaning that you can''t
change the contents of an existing string object. To change the value of
a string you have to replace it with a new string instance, which you
can not do unless you send the string by reference to the method.

What to make of ''generic delegate types''? After going through this
example carefully (which was a modification of a extremely primitive
example of generic delegate types taken from p. 108 of the C# 3.0
Nutshell, which formed the first output, involving squaring a value
type), I am convinced generic delegate types are a receipe for
disaster, since essentially they do away with strong typing (whatever
that means, but I have an understanding in my mind''s eye).

No, that is not correct. Generic delegate types are still strongly
typed. Just because the type is not specified in the method doesn''t mean
that it''s not strongly typed. The type still has to be known at compile
time.

The only advantage I can see is just a slick way of declaring a
delegate " public delegate T Transformer<T(T arg); " that will then
allow you to write methods/functions that obey this template of taking
a type T and returning a type T (whether the T is an int, a double, or
even an object), though the methods/functions are radically
different. These methods can then be called using the convention
below. Big deal. A receipe for disaster.

The real advantage is actually not the methods that you can call using
the delegate, but the methods that you can write that calls the delegate.

Big deal and a receipe for disaster is not unlike "lambda expressions"
and "anonymous delegates" (both topics I''m not that familiar with).
If anybody can relate how generic delegate types correlate with these
two topics it would be appreciated.

Lambda expressions is just syntactic sugar for anonymous methods.

The term "anonymous delegates" doesn''t really mean anything. It''s like
talking about literal values as "anonymous variables". The term is
anonymous methods, and as an anonymous method doesn''t have a name, the
only way to use it is by referencing it with a delegate.

An anonymous method is simply a way to write a method inlined in the
code, which then (for example) can be assigned to a delegate. Example:

// assigning a named method to a delegate:
Transformer<inttrans1 = ReturnX;
// assigning an anonymous method to a delegate:
Transformer<inttrans2 = delegate(int x) { return x; };

>
RL

(c) 2008, all rights reserved, by ''artistic license'' and void where
prohibited. For skolarly use only. The moral rights of the author are
preserved, whatever that means. Copyleft and free to use without
attribution.

// output

1X! 2X! 3X! 1Sq! 4Sq! 9Sq! 1Cb! 64Cb! 729Cb! //note this works as
expected, since 9x9x9 = 729, and each array element is being changed
as expected.

value now [X]: 2 //not what you want - baad!
value now [Square]: 2 //not what you want - baad!
value now [Cube]: 2 //not what you want - baad!
____________

value now [X]: 3 //not what you want - baad!
value now [Square]: 3 //not what you want - baad!
value now [Cube]: 3 //not what you want - baad!
_____UtilSquarer______

value now [UtilSquarer]: 9 //now works fine
value of string [UtilSquarer]: goodbye!
_____UtilStringChanger______

value of string [UtilStringChanger]: BAA_is_a_goodBuy! //string
changed properly (1 of 2 ways to change string; see below for ref
version)
__UtilStringChanger2AndMoreStaticVer__

values of string, int are [UtilStringChanger2AndMoreStaticVersion]:
anotherStrin
gHere! , 10001
Press any key to continue . . .
/////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace p108DelegatesCSNutshell
{
public delegate T Transformer<T(T arg);
public delegate T Uransformer<T(ref T arg); //slight name change
needed for ''ref'' version, otherwise won''t compile
class Program
{
static void Main(string[] args)
{
int[] values = new int[] { 1, 2, 3 };
int value = 2;
Util myUtil = new Util();

Util.Transform1(values, ReturnX); //dynamically hook
ReturnX

As the method is generic, you need to specify the type when you call it:

Util.Transform1<int>(values, ReturnX);

foreach (int i in values)
{
Console.Write(i + "X! ");
}

Util.Transform1(values, Square); //dynamically hook square
foreach (int i in values)
{
Console.Write(i + "Sq! ");
}

Util.Transform1(values, myUtil.Cube); //dynamically hook
cube

The Cube method should be static (se below), so you should specify the
delegate as "Util.Cube".

As you are sending a copy of the value in the variable, the method just
changes the copy and then throws it away.

foreach (int i in values)
{
Console.Write(i + "Cb! ");
}

Console.WriteLine("\n");
myUtil.Transform2(value, ReturnX);

Also a generic method, so you have to specify the type. The Transform2
method should be static (se below), so you should use the class name to
call it:

Util.Transform2<int>(value, ReturnX);

As you are sending a copy of the value in the variable, the method just
changes the copy and then throws it away.

Console.WriteLine("value now [X]: {0}", value);
myUtil.Transform2(value, Square);
Console.WriteLine("value now [Square]: {0}", value);
myUtil.Transform2(value, myUtil.Cube);
Console.WriteLine("value now [Cube]: {0}", value);

Console.WriteLine("____________ \n");

myUtil.Transform2(myUtil.j, ReturnX);

Sending a copy of a member of an object is the same as sending a copy of
a local variable. The method can still only change the copy.

Console.WriteLine("value now [X]: {0}", myUtil.j);
myUtil.Transform2(myUtil.j, Square);
Console.WriteLine("value now [Square]: {0}", myUtil.j);
myUtil.Transform2(value, myUtil.Cube);
Console.WriteLine("value now [Cube]: {0}", myUtil.j);

Console.WriteLine("_____UtilSquarer______ \n");

myUtil.Transform2(myUtil, myUtil.UtilSquarer);
Console.WriteLine("value now [UtilSquarer]: {0}",
myUtil.j);
Console.WriteLine("value of string [UtilSquarer]: {0}",
myUtil.s);

Console.WriteLine("_____UtilStringChanger______ \n");

myUtil.Transform3(ref myUtil, myUtil.UtilStringChanger);
Console.WriteLine("value of string [UtilStringChanger]:
{0}", myUtil.s);

The Transform3 method should be static (se below), so you should specify
the class name instead of an instance name.

As the method is generic, you have to specify the type when calling it.

The UtilStringChanger should be static (se below), so you should specify
the class name instead of an instance name.

>
Console.WriteLine("__UtilStringChanger2AndMoreStat icVer__
\n");
myUtil.Transform3(ref myUtil,
UtilStringChanger2AndMoreStaticVersion);
Console.WriteLine("values of string, int are
[UtilStringChanger2AndMoreStaticVersion]: {0} , {1}", myUtil.s,
myUtil.j);
}

static int ReturnX(int x)
{
return x;
}

static int Square(int x)
{
return x * x;
}

static Util UtilStringChanger2AndMoreStaticVersion(ref Util U)
{
U = new Util();

As you are immediately throwing away anything that was in the argument,
you should use "out" instead of "ref".

U.s = "anotherStringHere!";
U.j = 10001;
return U;

It''s pointless to both change the argument and return it.

}

}
}
/////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace p108DelegatesCSNutshell
{
class Util
{
public int j;
public string s;
public Util ()
{
s = "hi";
j = 3;
}

public static void Transform1<T>(T[] values, Transformer<Tt)
{
for (int i = 0; i < values.Length; i++)
values[i] = t(values[i]);
}
public int Cube(int x) { return x * x * x; }

The Cube method doesn''t use anything in the Util instance, so it should
be static.

public Util UtilSquarer(Util U)
{
U.j = U.j * U.j;
U.s = "goodbye!";

//U = new Util(); //next 3 lines won''t work here since ref
not passed
//U.j = U.j * U.j;
//U.s = "NoGo";

return U;

It''s pointless to both change the argument and return it.

>
}

public Util UtilStringChanger(ref Util U)

The UtilStringChanger method doesn''t use anything in the Util instance,
so it should be static.

{
U = new Util();
U.s = "BAA_is_a_goodBuy!";
return U;

It''s pointless to both change the argument and return it.

}
public void Transform2<T>(T value, Transformer<Tt)

The Transform2 method doesn''t use anything in the Util instance, so it
should be static.

{ value = t(value); }

Assigning the return value from the delegate call to the value variable
doesn''t serve any purpose. As the argument only contains a copy of the
value (regardless if the value is a value type value or a reference to a
reference type) it''s never used after the assignment.

>
public void Transform3<T>(ref T value, Uransformer<Tt)

The Transform3 method doesn''t use anything in the Util instance, so it
should be static.

{
value = t(ref value);

It''s pointless to both send the value variable by reference to the
delegate call and assigning the return value to it. Whatever the method
assigns to the argument, it will be overwritten by the return value.

}

}
}


--
G?ran Andersson
_____
http://www.guffa.com


这篇关于通用代理类型解释(示例)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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