簡體   English   中英

獲取類中聲明的變量名

[英]Get the declared variable name in a class

我想做這樣的事情 - 在那里我捕獲對象內部的原始聲明對象變量名稱。

 public class Foo
    {
        private string _originalDeclarer;
        
        public Foo(string originalDeclarer=nameof(this))
        {
            _originalDeclarer = originalDeclarer;
        }

        public string OriginalDeclarer
        {
            get => _originalDeclarer;
            set => _originalDeclarer = value;
        }
    }

    public static class Bar
    {
        public static void CreateFoos()
        {
            Foo GreenFoo = new Foo();
            Foo BlueFoo = new Foo();
            
            Console.WriteLine(GreenFoo);
            Console.WriteLine(BlueFoo);
            
            //Expected output
            // "GreenFoo"
            // "BlueFoo"
        }    
    }

以上可以理解是行不通的,我知道變量名沒有存儲在運行時元數據中,所以這個問題的一般答案是它無法完成。

也就是說,研究使我找到了幾種解決方法,我正在尋找最好的方法。

這個問題很好地完成了提案:

class Self
{
    public string Name { get; }

    public Self([CallerMemberName] string name = null)
    {
        this.Name = name;
    }
}

然后:

class Foo
{
    private Self me = new Self(); // Equivalent to new Self("me")

    public void SomeMethod()
    {
        // Can't use the default here, as it would be "SomeMethod".
        // But we can use nameof...
        var joe = new Self(nameof(joe));
    }
}

我還沒有測試以上是否有效,但缺點對我來說是有問題的。

我有 - 但我很難找到我在這個問題中找到的較早答案,其中名稱在編譯時被替換。

如果有人有解決這個問題的方法(即使它慢得可怕)或者知道編譯時替換的方式,我會非常感興趣。

如果我可以在方法中停止實例化,上述建議的解決方法對我有用。

編輯上下文這里是我使用普通枚舉的示例 - 我寧願用我自己的強類型類型替換枚舉:ConfiguredDatabase 是一個枚舉。

private Result<DatabaseConnectionStatus> TestDatabase(ConfiguredDatabase database)
        {
            SqlDataAccessLayer sqlDataAccessLayer = DetailsStore.DataAccessLayers.TryGetbyUId(database.ToString());

            if (sqlDataAccessLayer.ConnectionDetails.DataSource == string.Empty)
            {
                return Result.Failed($"Database connection is not configured for {database}", DatabaseConnectionStatus.NoConnectionConfigured);
            }
        }

查看您的最后一次添加,我不建議使用枚舉類型來確定您的數據庫。 如果您的枚舉類型在稍后階段刪除了值,則會出現問題,例如

enum ConfiguredDatabase
{
  Database1,
  // Database2, 
  Database3
}

現在 Database3 的值與過去 Database2 的值相同。 如果您為每個分配固定值,那么仍然可以在您的調用代碼中使用分配給 Database2 的值!

相反,我建議通過將接口傳遞給具體的類類型來堅持一些依賴注入原則。

例如,沿着這些路線的東西。

public interface IConfiguredDatabase
{
  string ConnectionString;
}

public Database1 : IConfiguredDatabase
{
  public Database1
  {
    ConnectionString = "Database One";
  }
  public string ConnectionString{get;set;}
}

public Database2 : IConfiguredDatabase
{
  public Database1
  {
    ConnectionString = "Database Two";
  }
  public string ConnectionString{get;set;}
}

private Result<DatabaseConnectionStatus> TestDatabase(IConfiguredDatabase database)
        {
            SqlDataAccessLayer sqlDataAccessLayer = DetailsStore.DataAccessLayers.TryGetbyUId(database.ConnectionString);

            if (sqlDataAccessLayer.ConnectionDetails.DataSource == string.Empty)
            {
                return Result.Failed($"Database connection is not configured for {database.ConnectionString}", DatabaseConnectionStatus.NoConnectionConfigured);
            }
        }

然后在其他地方你稱之為:

using (var d = new Database1()
{
  var result = TestDatabase(d);

...
}

我知道我的示例並不完全適合您的代碼,但我希望它能讓您了解我的建議。

如果您確實需要使用反射來確定您的調用屬性是什么,那么我建議您采用以下模式。 我在 MVVM 中將它用於 ViewModel 類,因此使用 OnPropertyChanging 和 OnPropertyChanging 事件,但我相信您會明白這個想法。

您可以調整 BaseClass.SetProperty 以調用其他代碼或引發事件以滿足您的需要。

public class BaseClass
{
    /// <summary>
    ///     Worker function used to set local fields and trigger an OnPropertyChanged event
    /// </summary>
    /// <typeparam name="T">Parameter class</typeparam>
    /// <param name="backingStore">Backing field referred to</param>
    /// <param name="value">New value</param>
    /// <param name="propertyName">Property that this value is applied to </param>
    /// <param name="onChanged">Event handler to invoke on value change</param>
    /// <param name="onChanging">Event handler to invoke on value changing</param>
    /// <returns></returns>
    protected bool SetProperty<T>(
        ref T backingStore, T value,
        [CallerMemberName] string propertyName = "",
        Action onChanged = null,
        Action<T> onChanging = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value)) return false;

        onChanging?.Invoke(value);
        OnPropertyChanging(propertyName);

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

    /// <summary>
    ///     INotifyPropertyChanging event handler
    /// </summary>
    public event PropertyChangingEventHandler PropertyChanging;

    /// <summary>
    ///     INotifyOnPropertyChanging implementation
    /// </summary>
    /// <param name="propertyName">Class property that is changing</param>
    protected void OnPropertyChanging([CallerMemberName] string propertyName = "")
    {
        var changing = PropertyChanging;

        changing?.Invoke(this, new PropertyChangingEventArgs(propertyName));
    }

    /// <summary>
    ///     INotifyPropertyChanged event handler
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    ///     INotifyPropertyChanged implementation
    /// </summary>
    /// <param name="propertyName">Class property that has changed</param>
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;

        changed?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

public class SomeClass : BaseClass
{
    private int _propertyOne;
    private string _propertyTwo;
    
    public int PropertyOne
    {
        get=> return _propertyOne;
        set=> SetProperty(ref _propertyOne, value);
    }
    
    public int PropertyTwo
    {
        get=> return _propertyOne;
        set=> SetProperty(ref _propertyTwo, value);
    }   
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM