2009-02-19 2 views
26

Могу ли я передать свойство как параметр «out» или «ref», если нет, то почему бы и нет?Можно ли передать свойства как параметры «out» или «ref»?

например.

Person p = new Person(); 

. . .

public void Test(out p.Name); 
+1

Пожалуйста перепечатывать ваш вопрос, чтобы сделать какой-то смысл ... –

+4

Это делает достаточно здравого смысла, что он получил разумный Ответ –

+0

Привет, на самом деле мой вопрос: Могу ли я передать свойство как параметр «выход» или «ref», если нет, то нет? пример. Лицо p = новое лицо(); public void Test (out p.Name); –

ответ

36

Извинения за короткий ответ, но нет, спецификация языка C# запрещает его.

См. Это answer на другой вопрос, чтобы узнать, что происходит, когда вы пытаетесь. В нем также говорится, почему вы не должны делать свойство просто публичным полем, чтобы обойти ограничение.

Надеется, что это помогает

EDIT: Вы спросите почему?

Передача переменной в параметр out или ref вы фактически передаете адрес (или местоположение в памяти) переменной. Внутри функции компилятор знает, где именно находится переменная, и получает и записывает значения на этот адрес.

Свойство выглядит как значение, но на самом деле это пара функций, каждая с другой подписью. Таким образом, чтобы передать свойство, вам действительно нужно передать два указателя на функции, один для get и один для набора.

То совсем другое дело передать в функцию, чем адрес переменной

т.е. один два указателя функции адрес переменной v в.

Update
Почему не C# просто смотреть после этого для нас?

Я не Eric Lippert, но мне придется идти на то, почему

Что следует сигнатура функции вы звоните быть?
Допустим, вы хотите позвонить void MyFn(ref int i), если это останется таким, или если оно изменится, чтобы сказать, что мы также разрешаем свойства? Если он изменится на некоторый синтаксис, например void MyFn(prop_ref int i), то это довольно бесполезно, вы не можете передавать свойства библиотечным функциям или сторонним кодам, которые не были написаны специальным модификатором prop_ref. В любом случае, я думаю, вы предполагаете, что это не должно быть иначе.

Теперь можно сказать, что MyFn передает i в функцию COM или вызов WinAPI, передавая адрес i (т. Е. За пределами .net, по ссылке). Если это свойство, как вы получаете адрес i? Не может быть никакого фактического int под свойством, чтобы получить адрес. Вы делаете то, что делает VB.Net?

Компилятор Vb.Net указывает, когда свойство передается в качестве аргумента ByRef методу. В этот момент он объявляет переменную, копирует свойство переменной, передает переменную byref, а затем после вызова метода копирует переменную обратно в свойство. то есть

MyFunc(myObject.IntProperty) 

становится

Dim temp_i As Integer = myObject.IntProperty 
MyFunc(temp_i) 
myObject.IntProperty = temp_i 

Каких-либо побочные эффекты свойства не произойдет до тех пор, MyFunc возвратов, что может вызвать всевозможные проблемы и привести к самых тонким ошибкам.

По моему скромному мнению решение Vb.Net для этой проблемы также нарушено, поэтому я не буду принимать это в качестве ответа.

Как вы думаете, компилятор C# должен справиться с этим?

+16

Это не работает. C# не является языком низкого уровня, поэтому параметр 'ref' не должен быть адресом, но на самом деле представляет собой пару замыканий, геттер и сеттер. Если вы передадите локальную переменную в качестве параметра 'ref', язык должен автоматически создать пару getter/setter. И все это должно быть скрыто от ничего не подозревающего программиста. – pyon

+0

@ Эдуардо Леон: Я обновил свой ответ. –

+1

@ EduardoLeón: Есть много вещей, которые могут быть сделаны с адресами, которые нельзя сделать с закрытием. Правильный способ позволить свойствам передаваться в качестве ссылок будет определять тип свойства, которое вместо того, чтобы содержать геттер и сеттер, будет выставлять адрес контролируемым образом (например, свойство типа T может иметь метод, который, учитывая делегат, который принял параметр ref типа T, передал бы адрес этого поля поддержки (или другого места хранения типа T) этому делегату. – supercat

0

Вместо этого, вы должны сделать что-то вроде этого

WhatEverTheType name; 

Test(out name); 

// Choose one of the following construction 

Person p = new Person(); 
p.Name = name; 

Person p = new Person(name); 
Person p = new Person(Name => name); 
+2

Да. Но ... ах, гораздо больше кода! – micahhoover

11

Другие объяснили, что вы не можете сделать это в C#. В VB.NET, вы можете сделать это, даже с возможностью строгого/явного на:

Option Strict On 
Option Explicit On 
Imports System.Text 

Module Test 

    Sub Main() 
     Dim sb as new StringBuilder 
     Foo (sb.Length) 
    End Sub 

    Sub Foo(ByRef x as Integer) 
    End Sub 

End Module 

Приведенный выше код эквивалентен этому C# код:

using System.Text; 

class Test 
{ 
    static void Main() 
    { 
     StringBuilder sb = new StringBuilder(); 
     int tmp = sb.Length; 
     Foo(ref tmp); 
     sb.Length = tmp; 
    } 

    static void Foo(ref int x) 
    { 
    } 
} 

Лично я рад, что C# не имеет этого - это много загрязняет воды, особенно с точки зрения значения свойства, если параметр задан в методе, но затем генерируется исключение.

РЕДАКТИРОВАТЬ: В соответствии с вашими соображениями, почему я считаю, что прохождение свойств в мутных водах. Если вы передаете нормальную переменную по ссылке, то эта переменная оценивается каждый раз, когда она ссылается в методе. Если значение по какой-либо причине изменяется (например, как побочный эффект какой-либо другой работы в методе), то это изменение будет немедленно видно в методе. Это не так, если вы передаете свойство по ссылке в VB.NET: свойство getter вызывается один раз, а затем вызывается средство setter. Это не похоже на то, что вы проходите в «вот свойство - получите и установите из этого всякий раз, когда вы используете параметр».

Вот полный пример, где проходит поле и сдав полностью тривиальное свойство в .NET имеют очень разные результаты:

Option Strict On 
Option Explicit On 
Imports System.Text 

Class Test 

    Dim counter as Integer 

    Property CounterProperty As Integer 
     Get 
      Return counter 
     End Get 
     Set (ByVal value as Integer) 
      counter = value 
     End Set 
    End Property 

    Sub Increment 
     counter += 1 
    End Sub 

    Shared Sub Main() 
     Dim t as new Test() 
     Console.WriteLine("Counter = {0}", t.counter) 
     t.Foo(t.counter) 
     Console.WriteLine("Counter = {0}", t.counter) 

     t.CounterProperty = 0 
     Console.WriteLine("CounterProperty = {0}", t.CounterProperty) 
     t.Foo(t.CounterProperty) 
     Console.WriteLine("CounterProperty = {0}", t.CounterProperty) 
    End Sub 

    Sub Foo(ByRef x as Integer) 
     x = 5 
     Increment 
     Increment 
     Increment 
     x += 1 
    End Sub 

End Class 
+2

Jon: Если вы не возражаете, не могли бы вы рассказать о своих мыслях о «грязной воде», я не понимаю, почему вы думаете, что передача свойств в параметры ref - это особенно плохая идея (я не говорю, что они хорошая идея). Спасибо друг. –

2

Еще одна причина этого не допускается происходит потому, что арбитр и параметра из чтения и записывается внутри метода, тогда как свойство может быть только для чтения/записи.

Person 
{ 
    public string Name { get { return "me"; } } 
} 

А что если вы можете это сделать?

Test(out p.Name);  

public void Test(out string name) 
{ 
    name = "someone else"; 
} 

Вы теперь не ты, а кто-то другой, но это против договора вы сделали с get свойства только Name (если когда-либо это работало). Это тот же случай с полями readonly-члена класса, вы не можете передать их ссылку.

Person 
{ 
    public readonly string name = "me"; 
} 

Test(out p.name); //not possible. 

Может быть C# может придумать для чтения/WriteOnly аргументы для метода:

public void Test(out settable string name, gettable int count, bool whatever) 
{ 
    name = "someone else"; 
} 

Test(out p.Name, 0, true); // doesnt compile since p.Name is readonly. 
+0

Я думаю, что вы слишком много слишком сокрушаете. Это просто не позволит свойства get-only передаваться с помощью ref или out, так же, как это не позволяет это произойти для полей readonly с ошибкой. –

 Смежные вопросы

  • Нет связанных вопросов^_^