Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用表达式使值类型充当引用类型<;Func<;T>&燃气轮机;_C#_.net_Expression - Fatal编程技术网

C# 使用表达式使值类型充当引用类型<;Func<;T>&燃气轮机;

C# 使用表达式使值类型充当引用类型<;Func<;T>&燃气轮机;,c#,.net,expression,C#,.net,Expression,我们知道int是一种值类型,因此以下内容很有意义: int x = 3; int y = x; y = 5; Console.WriteLine(x); //says 3. 现在,这里有一段代码,由于缺少更好的术语“链接”,我们希望将两个变量指向同一个内存位置 int x = 3; var y = MagicUtilClass.linkVariable(() => x); y.Value = 5; Console.WriteLine(x) //says 5. 问题是:方法linkVa

我们知道int是一种值类型,因此以下内容很有意义:

int x = 3;
int y = x;
y = 5;
Console.WriteLine(x); //says 3. 
现在,这里有一段代码,由于缺少更好的术语“链接”,我们希望将两个变量指向同一个内存位置

int x = 3;
var y = MagicUtilClass.linkVariable(() => x);
y.Value = 5;
Console.WriteLine(x) //says 5.
问题是:方法linkVariable看起来如何?它的返回类型是什么样的?

虽然,我给这篇文章的标题是“使值类型表现为引用类型”,但所述linkVariable方法也适用于引用类型,即

Person x = new Person { Name = "Foo" };
var y = MagicUtilClass.linkVariable(() => x);
y.Value = new Person { Name = "Bar" };
Console.WriteLine(x.Name) //says Bar.
我不知道如何在C#中实现这一点(顺便说一下,不允许使用不安全的代码)


欣赏创意。谢谢。

.NET中的整数是不可变的。我不确定你想用这个问题解决什么问题。您是否考虑过创建一个具有“包装”整数的属性的类?该类将是引用类型,您试图实现的功能不需要任何“魔法”实用程序类,只需要正常的C#引用类型行为。

您可以执行以下操作:

public delegate void Setter<T>(T newValue);
public delegate T Getter<T>();
public class MagicPointer<T>
{
    private Getter<T> getter;
    private Setter<T> setter;

    public T Value
    {
        get
        {
            return getter();
        }
        set
        {
            setter(value);
        }
    }

    public MagicPointer(Getter<T> getter, Setter<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }

}
CompilerGeneratedClass1 locals = new CompilerGeneratedClass1();
locals.x = 47;
var magic = MagicUtilClass.LinkVariable(() => locals.x);
// etc.
公共委托无效设置器(T newValue);
公共委托T Getter();
公共级魔法指挥员
{
私人消气剂;
私人二传员;
公共价值
{
得到
{
返回getter();
}
设置
{
设定器(值);
}
}
公共MagicPointer(Getter-Getter,Setter-Setter)
{
this.getter=getter;
this.setter=setter;
}
}
用法:

int foo = 3;
var pointer = new MagicPointer<int>(() => foo, x => foo = x);
pointer.Value++;
//now foo is 4
intfoo=3;
var指针=新的MagicPointer(()=>foo,x=>foo=x);
指针.Value++;
//现在福4岁了
当然,这个解决方案不能保证强大的编译时控制,因为要编写一个好的getter或setter取决于程序员


也许,如果您需要指针之类的东西,您应该重新考虑您的设计,因为您可能可以用另一种方式在C中实现它:

这里有一个完整的解决方案:

// Credits to digEmAll for the following code
public delegate void Setter<T>(T newValue);
public delegate T Getter<T>();
public class MagicPointer<T>
{
    private Getter<T> getter;
    private Setter<T> setter;

    public T Value
    {
        get { return getter(); }
        set { setter(value); }
    }

    public MagicPointer(Getter<T> getter, Setter<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
}

// Code starting from here is mine
public static class MagicUtilClass
{
    public static MagicPointer<T> LinkVariable<T>(Expression<Func<T>> expression)
    {
        var memberExpr = expression.Body as MemberExpression;
        if (memberExpr == null)
            throw new InvalidOperationException("The body of the expression is expected to be a member-access expression.");
        var field = memberExpr.Member as FieldInfo;
        if (field == null)
            throw new InvalidOperationException("The body of the expression is expected to be a member-access expression that accesses a field.");
        var constant = memberExpr.Expression as ConstantExpression;
        if (constant == null)
            throw new InvalidOperationException("The body of the expression is expected to be a member-access expression that accesses a field on a constant expression.");
        return new MagicPointer<T>(() => (T) field.GetValue(constant.Value),
                                   x => field.SetValue(constant.Value, x));
    }
}
int x = 47;
var magic = MagicUtilClass.LinkVariable(() => x);
magic.Value = 48;
Console.WriteLine(x);  // Outputs 48
要理解此解决方案的工作原理,您需要知道,每当在lambda表达式中使用变量时,编译器都会对代码进行相当大的转换(无论该lambda表达式是成为委托还是表达式树)。它实际上生成了一个包含字段的新类。变量x被删除并替换为该字段。使用示例将如下所示:

public delegate void Setter<T>(T newValue);
public delegate T Getter<T>();
public class MagicPointer<T>
{
    private Getter<T> getter;
    private Setter<T> setter;

    public T Value
    {
        get
        {
            return getter();
        }
        set
        {
            setter(value);
        }
    }

    public MagicPointer(Getter<T> getter, Setter<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }

}
CompilerGeneratedClass1 locals = new CompilerGeneratedClass1();
locals.x = 47;
var magic = MagicUtilClass.LinkVariable(() => locals.x);
// etc.

代码检索到的“字段”是包含x的字段,它检索到的“常量”是本地实例。

似乎与@GSerg很像。@GSerg-感谢链接,但这是另一种方式。当然,更改lambda中绑定的变量的大小和值会更改计算lambda的结果。我感兴趣的是在另一个东西中捕获的值,因此当另一个东西被修改时,原始的更改为,即,当y被更改时,x被更改。