2009-11-27 1 views
12

Хорошо, я буду вырезать и вставлять из .NET отражателем, чтобы продемонстрировать то, что я пытаюсь сделать:Почему я не могу передать свойство или индексатор в качестве параметра ref, когда отражатель .NET показывает, что это сделано в .NET Framework?

public override void UpdateUser(MembershipUser user) 
{ 
    //A bunch of irrelevant code... 

    SecUtility.CheckParameter(ref user.UserName, true, true, true, 0x100, "UserName"); 

    //More irrelevant code... 
} 

Эта строка кода приходит прямо из System.Web.Security.SqlMembershipProvider.UpdateUser (System. Web.dll v2.0.50727) в .NET Framework.

Для параметра SecUtility.CheckParameter требуется исходное значение в качестве первого параметра, которому передается свойство пользователя, переданного в качестве аргумента.

Определение кода CheckParameter является:

internal static void CheckParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName) 
{ 
    //Code omitted for brevity 
} 

Все это делает смысл - на бумаге ... так что я сколотить быстрый маленький прототип где-то я хотел бы использовать что-то подобное:

public class DummyClass 
{ 
    public string ClassName{ get; set; } 
} 

public class Program 
{ 
    private static DoSomething(ref string value) 
    { 
     //Do something with the value passed in 
    } 

    public static Main(string[] args) 
    { 
     DummyClass x = new DummyClass() { ClassName = "Hello World" }; 

     DoSomething(ref x.ClassName); //This line has a red squiggly underline 
             //under x.ClassName indicating the 
             //error provided below. 
    } 
} 

Этот код не будет компилироваться - ошибка показывает, как:

"A property or indexer may not be passed as an out or ref parameter" 

Достаточно справедливо ... но почему мой код не позволит мне делать что-то, что похоже на базу кода .NET Framework? Это ошибка с тем, как .NET Reflector интерпретирует DLL или это ошибка с тем, как я интерпретирую их код?

+0

Вы используете автоматическую собственность. Когда он компилируется, он превращается в две функции. Таким образом, структура не может передать ссылку на две функции во что-то другое. –

+0

@Yuriy - это было бы понятно. Однако в коде, который заставил меня заметить эту проблему, я использую * тот же класс MembershipUser, на который ссылается в Framework * точно так же *, - почему это можно сделать внутри рамки, но не снаружи? – BenAlabaster

+0

Где @JonSkeet, когда он вам нужен ... – BenAlabaster

ответ

15

Я думаю, что это некоторая плохая интерпретация из Reflector. На самом деле, если вы пишете код, как это:

static void Main(string[] args) 
{ 
    DummyClass x = new DummyClass(); 
    string username = x.ClassName; 
    DoSomething(ref username); 
} 

и скомпилировать его в режиме выпуска вы увидите это в Рефлектор:

static void Main(string[] args) 
{ 
    DummyClass x = new DummyClass(); 
    DoSomething(ref x.ClassName); 
} 

Помните, что C# компилятор не производит C# код, но IL так что вы видите, что в Reflector не всегда есть реальность. Таким образом, чтобы четко понимать, что происходит под капотом, вы можете посмотреть на реальный код, созданный компилятором:

L_000f: callvirt instance string System.Web.Security.MembershipUser::get_UserName() 
L_0014: stloc.0 
L_0015: ldloca.s str 
L_0017: ldc.i4.1 
L_0018: ldc.i4.1 
L_0019: ldc.i4.1 
L_001a: ldc.i4 0x100 
L_001f: ldstr "UserName" 
L_0024: call void System.Web.Util.SecUtility::CheckParameter(string&, bool, bool, bool, int32, string) 

Очевидно, что используется локальная переменная.

+0

@Darin - но разве это не семантически отличается? Не является ли теперь именем пользователя x.ClassName, и мы передаем ссылку на строку «имя пользователя», а не ссылку на строку «x.ClassName» ... – BenAlabaster

+0

@Darin - этот выпуск кода режима освобождения теперь имеет меня царапая мою голову ... как она меняет код на то, что я не могу закодировать сам, потому что компилятор этого не позволяет? – BenAlabaster

+0

То же самое в режиме отладки :-) –

1

Попробуйте установить значение свойства переменной, прежде чем передавать его функции.

string myClassName = x.ClassName 
DoSomething(ref myClassName); 

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

+0

@Kyle - я уже написал это как семантически другое. Потому что я был после ссылки на x.ClassName. myClassName теперь будет копией строки, и я передам ссылку на копию. Но теперь @Darin Dimitrov заставляет меня задуматься о компиляции режима выпуска ... – BenAlabaster

6

Это ошибка рефлектора. Это не передача собственности по ссылке.

Вот код C#, который будет воспроизводить его.

using System; 

class Person 
{ 
    public string Name { get; set; } 
} 

class Test 
{ 
    static void Main(){} // Just make it easier to compile 

    static void Foo(Person p) 
    { 
     string tmp = p.Name; 
     Bar(ref tmp); 
    } 

    static void Bar(ref string x) 
    { 
    } 
} 

Отражатель показывает этот код Foo:

private static void Foo(Person p) 
{ 
    Bar(ref p.Name); 
} 

Не только это недопустимый C#, но это вводит в заблуждение - было бы предположить, что изменения, внесенные в x в пределах Bar бы как-то изменить p.Name - где это не случай, когда вы смотрите на исходный код C#.

В вашем оригинальном образце это имеет еще меньшее значение, так как UserName - это свойство только для чтения!

+0

Спасибо за ваш вклад :) – BenAlabaster

+0

Мой оригинальный образец разрезан и вставлен прямо из отражателя, и это заставило меня почесывать голову – BenAlabaster

+0

, когда я говорю «от отражателя», Я имею в виду, конечно, интерпретацию .NET Reflector System.Web.dll (v2.0.50727) »- Я знаю, что вы приверженец точной терминологии: P – BenAlabaster

0

Когда вы передаете переменную как ref или out, вызов фактически указывает на память, где он изначально расположен. Поэтому, если вам разрешено передать свойство в качестве ссылки, это означает, что вы делаете член класса непоследовательным. Это и есть причина этой проблемы.

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

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