【问题标题】:C# how swap object to object of inherite class with only their reference - It is posible?C# 如何将对象交换为仅具有引用的继承类的对象 - 有可能吗?
【发布时间】:2015-01-15 20:27:36
【问题描述】:

编辑:考虑到我无权访问列表

编辑:我将示例更改为更高级

编辑:固定示例;P

编辑:再次编辑 我确定我被否决了,因为你们不了解我的考虑的起源。我知道它可以在 C++ 中使用指针,但不确定它在 C# 中是否仍然可行。而且我没有问因为我不知道如何更改列表中的元素!我只想在无法访问该列表的情况下完成它!这只是一个例子,因为真实的例子很复杂,在这里介绍......

我想知道是否可以做这样的事情 Foo 类 { 公共 int foo = 100; 事件处理程序;

        public Foo()
        {
            something += smth;
        }

        public void doSmth()
        {
            something(this, EventArgs.Empty);
        }

        public static void smth(object sender, EventArgs e)
        {
            sender = new Foo();
        }
    }

    class Boo : Foo
    {
        EventHandler<EventArgs> something;

        public Boo()
        {
            foo = 1;
            something += smth;
        }           

    }
    static void Main(string[] args)
    {
        List<Foo> list = new List<Foo>();

        Foo foo = new Boo();
        list.Add(foo);

        foreach (Foo f in list)
            f.doSmth();

        foreach (Foo f in list)
            Console.WriteLine(f.foo);

        Console.ReadKey();
    }

我的输出是 1,但我想得到 100。可以通过引用从列表中更改对象吗?

【问题讨论】:

  • 我不明白为什么我现在会被否决,当我刚刚编辑我的示例时,这不是微不足道的问题。也许那样做是不可能的,但你可以在投反对票时发表评论
  • 我也不确定。这不完全是一个模范问题,但 -5 似乎有点苛刻。
  • 在我看来,您根本无权访问该列表。如果您只能访问您知道在列表中的对象,但没有对实际列表的引用,则不可能将某些内容插入列表中。这是另一个可能感兴趣的问题:stackoverflow.com/questions/776430/…

标签: c# pointers reference


【解决方案1】:

是的,但你没有得到你想的参考:

Foo boo = list[0];
boo = new Boo;      

这会创建一个 引用(称为 boo)并将list[0] 中的引用分配给它。然后将Boo 对象分配给该新的本地 引用。当您遍历List 时,存储在那里 的引用根本没有改变,所以您会看到这种行为。

相反,只需写:

list[0] = new Boo();

注意我实际上并不确定这是否可行,因此我对其进行了测试,它确实有效!因为代码有点奇怪,我建议找到一种不同的方式来改变它(比如删除旧对象并添加一个新对象)以提高可读性/可维护性。

        List<FancyText> test = new List<FancyText>();
        test.Add(new FancyText { Text = "test" });
        test[0] = new FancyText() { Text = "final" };

集合中包含有“final”的对象。

更新对于您的编辑,您几乎可以这样做:

private delegate void refHandler (ref Award sender);
private event refHandler test;

但是,您不能将 this 作为 ref 参数传递,因为它是只读的(有道理,对吗?您不能将自己分配给其他东西,那会很奇怪)。

【讨论】:

  • 是的,我知道,但出于考虑,我无权访问列表
  • @KarolChudzik 如果它是一个函数参数,那么您可以按照 Selman 的建议使用 ref。这就是你能做的最好的事情了。
  • Yhym 但这不是函数参数
  • @KarolChudzik 那你就卡住了。也许提供更接近实际代码的内容会帮助我们帮助您。
  • 请寻找新的更高级的例子
【解决方案2】:

不,这是不可能的。当您分配新引用时,boo 不再引用旧位置,但 list[0] 仍然在那里保留引用,更改 boo 的引用不会影响它。因为它们之间没有联系,您可以将它们视为两个不同的变量,它们持有对同一位置的引用。像这样:

string foo = "foo";
string bar = foo;
bar = "bar";

更改bar 的引用不会影响foo。那是行为或引用类型。只有在函数参数中使用 ref 修饰符时才能更改变量引用。请查看此问题以获取更多信息:What is the use of “ref” for reference-type variables in C#?

【讨论】:

  • @downvoter,请注意解释是否有问题。或者,如果您只是无缘无故投了反对票,请告诉我,这样我就可以停止思考我的回答可能有什么问题。
  • 我以为你有一个很好的答案。不知道为什么人们在这里对答案投反对票(由于某种原因,另一个除外)。我有 2 个后来被删除。
【解决方案3】:

这与继承无关。您根本就没有修改过列表。看这段代码:

Foo boo = list[0];
boo = new Boo();

在第一行之后,boo 指的是与list 中的第一个元素相同的内存对象。但是在 second 行之后,它引用了一个 new 内存对象。 不是列表中的第一个元素。在调试器中停下来检查对象和列表,它们是不同的。

然后您继续打印列表中的元素。你永远不会打印boo 的值,也永远不会修改列表。要更新列表中的元素,您需要对其进行设置:

list[0] = boo;

编辑:您更新的示例甚至无法编译。此代码不起作用:

foreach (Foo f in list)
    f.doSmth();

因为在Foo 上没有调用doSmth() 的方法。您是否尝试检查集合中的任何给定元素是否是 Boo 的实例,如果是则调用该方法?在这种情况下,您可以检查类型:

foreach (Foo f in list)
    if (f is Boo)
        (f as Boo).doSmth();

虽然在大多数情况下,我认为这并不是真正好的设计。当然,有些情况需要它。但是您的FooBoo 建模更有可能在某处破坏了抽象。如果集合是Foo 类型,那么对该集合的任何操作应该只允许用户对Foo 类型进行操作。

【讨论】:

  • 是的,我知道,但考虑到我无权访问列表。
  • @KarolChudzik:这没有意义。如果您“无权访问”数组,那么您首先如何从中获取值?也许您的示例实际上并没有说明问题?
  • 这个例子没有说明问题,我会编辑帖子。但知道这将是一个奇怪的例子;)
  • 请寻找新的更高级的例子
  • 已修复,请看 :)
【解决方案4】:

下面将创建一个变量boo,并在list 的第一个位置引用Foo 对象,即您所做的第一个new Foo()

Foo boo = list[0];

当您执行以下操作时,您将使用新构造的 Boo 对象的引用覆盖变量 booFoo 对象的引用。

boo = new Boo;

要执行手动测试的具体要求,您可以执行以下操作

Foo boo = list[0] == new Boo();

这将更新变量boolist 中的第一个位置,并使用对新创建的 Boo 对象的新引用。这将输出:

1
100

现在,说到这里。在技​​术上可以直接使用 unsafefixed 关键字来使用引用。这将增加几个限制。这是我使用不安全代码复制代码的最佳尝试:

//Requres project properties be set to Allow Unsafe Code
struct Foo
{
    public int Bar { get; set; }
}

static unsafe void Main(string[] args)
{
    Foo[] list = new Foo[2];
    list[0] = new Foo { Bar = 100 };
    Foo foo = new Foo { Bar = 100 };
    list[1] = foo;

    fixed (Foo* boo = list)
        *boo = new Foo { Bar = 1 };

    foreach (Foo f in list)
        Console.WriteLine(f.Bar); //Prints 1 then 100

    Console.ReadKey();
}

这也会输出:

1
100

然而,这并不是一个普遍的例子。如果您想指向列表中 0 以外的索引,会发生什么情况。您必须将 fixed 部分替换为以下内容:

fixed (Foo* plist = list)
{
    const int offset = 1;
    Foo* boo = plist + offset;
    *boo = new Foo { Bar = 1 };
}

这将输出:

100
1

你失去的是引用类对象,只有结构,这意味着没有继承,并且必须使用 fixed 关键字,可能还有更多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 2021-03-29
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多