-5

EDIT: In considerations i didn't have access to list

EDIT: I changed example to more advanced

EDIT: Fixed example ;P

EDIT: Again edited I'm sure that i got vote down cause you guys didn't understand orgin of my considerations. I know it is posible with pointers in C++ but not sure it is still posible in C#. And i didnt ask cuase i don't know how to change element in List! I just want to make it without access to that LIST! This is only example cuase real live example is to complicated to introduce here...

I Wonder if it's posible to do something like this class Foo { public int foo = 100; EventHandler something;

        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();
    }

My output is 1 but i want to get 100. It is posible to change object from list by its reference ?

Karol Chudzik
  • 91
  • 1
  • 1
  • 10
  • I don't understand why i get downvote now, when i just edited my example and it isn't trivial problem. Maybe it is impossible to do this in that way, but you can comment when you vote down – Karol Chudzik Jan 15 '15 at 21:18
  • I'm not sure either. Its not exactly a model question, but -5 seems a little harsh. – BradleyDotNET Jan 15 '15 at 21:19
  • It seems to me that you don't have access to the list at all. If you only have access to an object you know is in a list, but no reference to the actual list it is impossible to insert something into the list. Here's another question which might be of interest: http://stackoverflow.com/questions/776430/why-is-the-iteration-variable-in-a-c-sharp-foreach-statement-read-only – André C. Andersen Jan 15 '15 at 22:45

4 Answers4

2

Yes, but you didn't get the reference you thought:

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

This makes a new reference (called boo) and assigns the reference in list[0] to it. You then assign a Boo object to that new, local reference. When you iterate over the List, the reference stored there hasn't been changed at all, so you see the behavior.

Instead, just write:

list[0] = new Boo();

Note I actually wasn't sure that would work, so I tested it, and it does! Because the code is kind of odd, I would reccommend finding a different way to mutate it (like removing the old object and adding a new one) in order to improve readability/maintainability.

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

The collection holds the object with "final" in it.

Update To your edit, you can almost do that:

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

However, you can't pass this as a ref parameter, as it is read-only (makes sense, right? you can't assign yourself to something else, that would be weird).

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
1

No it is not possible. When you assign a new reference boo is no longer referencing the old location, but list[0] still holds a reference there and changing boo's reference doesn't affect it. Because there is no connection between them, you can think them as two different variables that holds a reference to the same location. Like this:

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

Changing the reference of bar does not affect foo. That's the behaviour or reference types. Changing a variables reference would be only possible when you use ref modifier in function parameters.Have a look at this question for more info about that: What is the use of “ref” for reference-type variables in C#?

Community
  • 1
  • 1
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • @downvoter, care to explain if there is something wrong. or if you just downvoted without any reason let me know so I can stop thinking what might be wrong about my answer. – Selman Genç Jan 15 '15 at 21:11
  • I thought you had a good answer. Not sure why people are downvoting answers here (except the other one for some reason). I've had 2 that were later removed. – BradleyDotNET Jan 15 '15 at 21:17
0

This has nothing to do with inheritance. You simply never modified the list. Look at this code:

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

After the first line, boo refers to the same in-memory object as the first element in list. But after the second line, it refers to a new in-memory object. Not the first element in the list. Stop there in a debugger and examine both the object and the list, they're different.

Afterward you then go on to print the elements from the list. You never print the value of boo, and never modify the list. To update the element in the list, you need to set it:

list[0] = boo;

Edit: Your updated example doesn't even compile. This code won't work:

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

Because there is no method called doSmth() on Foo. Are you trying to check if any given element in the collection is an instance of Boo and invoke the method if it is? In that case you can check the type:

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

Though in most cases I'd argue that isn't really good design. There are cases which call for it, sure. But it's more likely that your Foo and Boo modeling are breaking an abstraction somewhere. If the collection is of type Foo then any operation on that collection should only user operations on type Foo.

David
  • 208,112
  • 36
  • 198
  • 279
0

The following will create a variable boo with a reference to the Foo object in the first spot in list, i.e., the first new Foo() you did.

Foo boo = list[0];

When you do the following you overwrite the variable boo's reference to the Foo object with a reference to your newly constructed Boo object.

boo = new Boo;

To do what your manual test specifically is asking for, you could do the following

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

This will update both the variable boo and the first spot in list with a new reference to your newly created Boo object. This will output:

1
100

Now, when this is said. It is technically possible to use references directly using the unsafe and fixed keywords. This will add several restrictions. Here is my best attempt at replicating your code using unsafe code:

//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();
}

This will also output:

1
100

However, it isn't really a general example. What happens if you want to point to an index other than 0 of the list. You'd have to swap out the fixed part with something like the following:

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

This would output:

100
1

What you lose is referencing class objects, only structs, this means no inheritance, and having to use the fixed keyword, and probably much more.

André C. Andersen
  • 8,955
  • 3
  • 53
  • 79