Могу ли я передать свойство как параметр «out» или «ref», если нет, то почему бы и нет?Можно ли передать свойства как параметры «out» или «ref»?
например.
Person p = new Person();
. . .
public void Test(out p.Name);
Могу ли я передать свойство как параметр «out» или «ref», если нет, то почему бы и нет?Можно ли передать свойства как параметры «out» или «ref»?
например.
Person p = new Person();
. . .
public void Test(out p.Name);
Извинения за короткий ответ, но нет, спецификация языка 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# должен справиться с этим?
Это не работает. C# не является языком низкого уровня, поэтому параметр 'ref' не должен быть адресом, но на самом деле представляет собой пару замыканий, геттер и сеттер. Если вы передадите локальную переменную в качестве параметра 'ref', язык должен автоматически создать пару getter/setter. И все это должно быть скрыто от ничего не подозревающего программиста. – pyon
@ Эдуардо Леон: Я обновил свой ответ. –
@ EduardoLeón: Есть много вещей, которые могут быть сделаны с адресами, которые нельзя сделать с закрытием. Правильный способ позволить свойствам передаваться в качестве ссылок будет определять тип свойства, которое вместо того, чтобы содержать геттер и сеттер, будет выставлять адрес контролируемым образом (например, свойство типа T может иметь метод, который, учитывая делегат, который принял параметр ref типа T, передал бы адрес этого поля поддержки (или другого места хранения типа T) этому делегату. – supercat
Вместо этого, вы должны сделать что-то вроде этого
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);
Да. Но ... ах, гораздо больше кода! – micahhoover
Другие объяснили, что вы не можете сделать это в 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
Jon: Если вы не возражаете, не могли бы вы рассказать о своих мыслях о «грязной воде», я не понимаю, почему вы думаете, что передача свойств в параметры ref - это особенно плохая идея (я не говорю, что они хорошая идея). Спасибо друг. –
Еще одна причина этого не допускается происходит потому, что арбитр и параметра из чтения и записывается внутри метода, тогда как свойство может быть только для чтения/записи.
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.
Я думаю, что вы слишком много слишком сокрушаете. Это просто не позволит свойства get-only передаваться с помощью ref или out, так же, как это не позволяет это произойти для полей readonly с ошибкой. –
Пожалуйста перепечатывать ваш вопрос, чтобы сделать какой-то смысл ... –
Это делает достаточно здравого смысла, что он получил разумный Ответ –
Привет, на самом деле мой вопрос: Могу ли я передать свойство как параметр «выход» или «ref», если нет, то нет? пример. Лицо p = новое лицо(); public void Test (out p.Name); –