.NET / C #: возможно ли заменить один объект в памяти другим? - PullRequest
2 голосов
/ 25 августа 2011

Возьмите этот код, например:

class Jooky
{
    static long Last;
    public Jooky() { Id += Last++; }
    public long Id { get; set; }
    public string Name { get; set; }
}

class Flooky
{
    public Flooky() { Jooky1 = new Jooky(); Jooky2 = new Jooky(); }
    public Jooky Jooky1 { get; set; }
    public Jooky Jooky2 { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        List<Flooky> Flookies = new List<Flooky>();

        //I build a collection of flookies to emulate the service call of
        //FlookyProxy.GetAllFlookies().
        for (int i = 0; i < 5; i++) Flookies.Add(new Flooky());

        //This makes a collection of all the jookies in all the flookies.
        var Jookies = Flookies.Select(f => f.Jooky1).Union(Flookies.Select(f => f.Jooky2));

        //I get the jooky.
        Jooky Jooky = Jookies.Single(j => j.Id == 2);

        //Fig 1: I just got a jooky out of the collection. One of the flookies
        //has a reference to this jooky. I want to set the jooky to a new
        //reference, but still want the same flooky to reference it.
        Jooky = new Jooky { Name = "Bob" };

        //I get the jooky again
        Jooky = Jookies.Single(j => j.Id == 2);

        //However, this writes an empty string because only the Jooky variable
        //I previously declared was affected.
        Console.WriteLine(Jookies.Single(j => j.Id == 2).Name);

        //Basically, I want the code in Fig 1 above to be the same as:
        //Flooy.Jooky = new Jooky { Name = "Bob" };

        Console.Read();
    }
}

По сути, переменная A ссылается на Aa в памяти, а переменная B ссылается на объект Bb в памяти. Я хочу, чтобы A ссылался на тот же объект в памяти, что и B, без перехода на A = B;. Вместо этого я хочу заменить физический объект в памяти другим, в конечном итоге, как Aa = Bb;.

Это вообще возможно?

Обновление: Основное правило: я не могу напрямую ссылаться на глупца, поэтому я не могу быть похож на Flooky.Jooky1 = new Jooky() или Flookies[3].Jooky1 = new Jooky().

Ответы [ 6 ]

4 голосов
/ 26 августа 2011

Возможно, это возможно с небезопасным кодом, предложенным havardhu, но это определенно невозможно с безопасным кодом. Важно понимать, почему делать то, что вы пытаетесь сделать, небезопасно. Это не только нарушает инкапсуляцию, но и нарушает безопасность типов. Рассмотрим этот пример.

class Me : IHaveCar
{
    BuickCentury myCentury = new BuickCentury(2004);

    public Car Car { get { return myCentury; } }

    public void Drive()
    {
        myCentury.CruiseWithAuthority();
    }
}

class EvilOilChangeService
{
    public void ChangeOil(IHaveCar customer)
    {
        Car car = customer.Car;
        // here's the fictional "replace object in memory" operator
        car <<== new VolkswagenBeetle(2003);
    }
}

EvilOilChangeService может создать ситуацию, когда myCentury ссылается на VolkswagenBeetle! У меня будут проблемы, когда я попытаюсь выбрать Drive, потому что VolkswagenBeetle просто не может CruiseWithAuthority, как BuickCentury (особенно если драйвер 6'2 ")

Даже в C / C ++, который разрешает произвольный доступ к памяти, я все равно был бы весьма удивлен кодом, который делает то, что вы хотите. Вот почему большинство других ответов предлагают другой подход или дизайн.

4 голосов
/ 25 августа 2011

Изменение:

//Jooky = new Jooky { Name = "Bob" };
Jooky.Name = "Bob" ;

Результатом .Single() является ссылка на экземпляр (объект).Вы просто перезаписывали ссылку одним новым объектом.Старый объект не был изменен или перезаписан.

Чтобы понять, что происходит и настроить то, к чему вы стремитесь, посмотрите «Тип значения и тип ссылки».Много чтения, чтобы сделать.


После прочтения комментария:

Если ваши Детали (Jookies) будут меняться независимо от их Владельцев (Flookies), то вам просто необходим еще один уровень косвенности.

Простое предложение:

  • не хранить ссылки на детали (так как они изменятся)
  • вместо этого хранить DetailId (JookyId1, JookyId2)
  • сохранить подробности в словаре (Dictionary<int,Jooky>)
  • создать свойство (только для чтения) в Owner, чтобы получить Detail1, просмотрев его в словаре.
3 голосов
/ 25 августа 2011

Вы можете написать небезопасный код на C #, который позволяет работать с прямой памятью.

Посмотрите здесь детали:

Указатели и массивы в C #

Вы заметите, что можете использовать знакомые указатели (*) и адреса (&) из C и C ++.

Вот пример небезопасного обмена, который, по-моему, вам нужен: Небезопасный своп в C #

0 голосов
/ 25 августа 2011

Если у вас есть доступ к классу Jookie, вы можете добавить свойство, которое содержит родительский элемент Flookie Jookie:

class Jooky 
{
    static long Last;
    public Jooky(Flooky parent) 
    {
        Id += Last++; 
        Parent = parent;
    }
    public long Id { get; set; }
    public string Name { get; set; }
    public Flooky Parent { get; private set; }
}

, а затем получить доступ к родительскому элементу Flookie иизменить его Jookie1 свойство:

Flookie flookie = Jookies.Single(j => j.Id == 2).Parent;
flookie.Jookie1 = new Jookie { Name = "Bob" }
0 голосов
/ 25 августа 2011

Когда вы работаете со ссылками, каждое присвоение ссылки изменяет объект, на который указывает ссылка.

Итак, когда вы говорите:

Jooky Jooky = Jookies.Single(j => j.Id == 2);

вы создаете ссылку на Джуки с Id == 2.И затем, когда вы говорите Jooky = new Jooky { Name = "Bob" };, вы говорите, что созданная вами ссылка указывает на Jooky, который вы только что создали.

Итак, если вы хотите установить новое значение в Jookie1Свойство (которое является заполнителем для ссылки на объект Jookie) объекта Flookies[0], вы должны сказать:

Flookies[0].Jooky1 = new Jooky { Name = "Bob" }; (как указано в ответе @Ashley John).

Таким образом, вы указываете Flookies[0].Jooky1 ссылку , чтобы указывать на объект new Jooky { Name = "Bob" };.

Более подробное объяснение см. http://msdn.microsoft.com/en-us/library/ms173104.aspx.

0 голосов
/ 25 августа 2011
Jooky = new Jooky { Name = "Bob" }; 
Flookies[0].Jooky1=Jooky;

Если вы хотите заменить и возразить другим, не назначая ссылки, просто скопируйте все поля данных в другой объект.Не уверен, правильно ли я понял ваш вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...