10

これが私のコードです:

public class UserPreferences
{
    /// <summary>
    /// The EMail signature.
    /// </summary>
    [UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
    public static string Signature
    {
        get
        {
            return UserPreferenceManager.GetValue();
        }

        set
        {
            UserPreferenceManager.SetValue(value);
        }
    }
}

public static string GetValue()
{
    if (((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID == null)
    {
        throw new Exception("Missing Operator ID");
    }

    string value = string.Empty;

    var frame = new StackFrame(1);  ***** <------ problem here.....

    var property = frame.GetMethod();
    var propertyname = property.Name.Split('_')[1];
    var type = property.DeclaringType;   ***** <------ problem here.....
    if (type != null)
    {
        var userPreference = typeof(UserPreferences).GetProperty(propertyname).GetCustomAttributes(true).FirstOrDefault() as UserPreferencePropertyAttribute;

        if (userPreference != null)
        {
            string category = userPreference.Category;
            string description = propertyname;
            value = GetValue(category, description, ((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID);
            if (value == null)
            {
                // always return something
                return userPreference.DefaultValue;
            }
        }
        else
        {
            throw new Exception("Missing User Preference");
        }
    }

    return value;
}

GetValueメソッド内では、StackFrameはリリースモードとデバッグモードで動作が異なります。

デバッグモードでは、プロパティ名を署名として正しく取得します

ただし、リリースモードでは、プロパティ名はGetUserPreferenceValueTestです。これは、クライアントとして呼び出しを行うテストメソッドであるためです。

したがって、私のコードはデバッグモードでは機能しますが、リリースモードでは失敗します。

Q. How can I use StackFrame properly so it works in Debug vs. Release modes. 

Q. Is there any other way to get calling property name and related information at run time?
4

2 に答える 2

8

私は一度同様の質問に答えました、ここで私の答えを読んでください。

要するに、あなたの方法は偽善者であるため、これは非常に悪い設計上の決定です。それは、異なる発信者とは異なる話し方をしますが、オープンにそれを伝えません。APIは、誰が呼び出すかに依存してはなりません。yieldまた、コンパイラはラムダなどの言語機能のために予期しない方法でスタックトレースを壊す可能性があるawaitため、これがリリースモードで機能したとしても、いつかは確実に壊れます。

メソッドに情報を渡すために設計された言語機能(<strong>メソッドパラメータ)を使用する代わりに、複雑な間接メカニズムを効果的に構築しています。

なぜ属性を使用するのですか?他の場所で読んでいますか?

その場合、呼び出す"Email"パラメーターと属性値の両方を繰り返したくない場合は、プロパティをに渡すことを検討してください。これにより、属性が抽出されます。これはソリューションに似ていますが、明示的です。GetValueExpression<>GetValue

[UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
public string Signature
{
    get { return GetValue (prefs => prefs.Signature); }
    set { SetValue (prefs => prefs.Signature, value); }
}

この回答は、これを実装する方法を示しています。

コードをチェックThread.CurrentPrincipalインしているようです。繰り返しになりますが、プロパティにアクセスすると例外が発生する可能性があることはクライアントコードには明らかではないため、これは実際には良い方法ではありません。これは、あなたのコードをサポートする誰かにとってデバッグの悪夢になるでしょう(そして私を信じてください、あなたが別のプロジェクトに移動した後、あなたのコードは何年も本番環境で実行されるかもしれません)。

代わりに、設定クラスのコンストラクターにVTXIdentity パラメーターを作成する必要があります。これにより、呼び出し元のコードは、このレベルでセキュリティを実施していることを認識し、定義上、このトークンを取得する場所を認識します。また、これにより、プロパティにアクセスするときではなく、何かが間違っていることがわかったらすぐに例外をスローできます。これは、コンパイルエラーがランタイムエラーよりも優れているように、メンテナがエラーを早期にキャッチするのに役立ちます。

最後に、これは楽しい演習ですが、C#で構成を保存および読み取るための、パフォーマンスが高くテスト済みのソリューションがたくさんあります。なぜあなたは車輪の再発明が必要だと思いますか?

于 2012-12-29T00:30:29.763 に答える
5

問題が、独自のライブラリをロールするのではなく、別のライブラリを使用できるかどうかの議論を乗り越えたと仮定します... C#5&.NET 4.5を使用していることに気付いた場合は、CallerMemberName属性を確認してください。CallerMemberNameを使用すると、GetValue()メソッドのシグネチャを次のように変更できます。

public static string GetValue([CallerMemberName] string callerName = "")

その後、プロパティはパラメータなしでGetValue()を呼び出すことができ、必要に応じてGetValue()に渡されるプロパティ名を取得します。

于 2012-12-29T00:55:04.063 に答える