簡體   English   中英

如何使用反射獲取抽象“const”屬性的值?

[英]How to get value of abstract “const” property using reflection?

我有一個像這樣定義的類:

public abstract class Uniform<T>
{
    public abstract string GlslType { get; }
    ...
}

然后是這樣定義的子類:

public class UniformInt : Uniform<int>
{
    public override string GlslType
    {
        get { return "int"; }
    }
}

然后在其他地方看起來像這樣的方法:

    public static string GetCode<T>()
    {
        var sb = new StringBuilder();
        var type = typeof(T);
        sb.AppendFormat("struct {0} {{\n", type.Name);
        var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach(var f in fields)
        {
            sb.AppendFormat("    {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(???), f.Name);
        }
        ...
    }

我在填寫???遇到了麻煩 秒。 我相信GetValue需要一個對象的實例,但我並不關心它是什么實例,因為它們都返回相同的值。 而且AFAIK沒有public abstract static readonly值這樣的東西,所以我必須使用屬性。

那么我能代替那些??? s返回“int”(假設一個字段是UniformInt )。

作為一方:我如何將fields限制為僅繼承Uniform<>字段類型?

您需要一個UniformInt實例才能獲取非靜態屬性的值:

UniformInt someUniformInt = ...
f.FieldType.GetProperty("GlslType").GetValue(someUniformInt, null)

作為一方:如何將字段限制為僅繼承Uniform的字段類型?

bool isDerivesFromUniformOfInt = typeof(Uniform<int>)
    .IsAssignableFrom(f.FieldType);

或者如果您事先不知道T的類型:

bool isDerivesFromUniformOfT = typeof(Uniform<>)
    .MakeGenericType(typeof(T))
    .IsAssignableFrom(f.FieldType);

問題是,由於您的屬性不是靜態的,編譯器不知道它們都返回相同的值。 由於您的UniformInt未被密封,因此另一個用戶可以繼承它並覆蓋GlslType以返回其他內容。 然后, UniformInt和所有派生類可用於UniformInt GetCode<T>()方法。

靜態方法確實是最好的選擇。 為了確保你在所有類上實現它們(你不能強迫它,因為靜態方法不能是抽象的)我會寫一個簡單的單元測試,它使用反射來加載從Uniform<T>繼承的所有類並檢查是否他們定義了靜態屬性。

UPDATE

在考慮屬性如何提供幫助時,經過一些實驗,我想出了以下內容。 它肯定不會贏得選美比賽,但作為一個學習練習,它是有幫助的;)

using System;
using System.Linq;

namespace StackOverflow
{
    internal class StackOverflowTest
    {
        private static void Main()
        {
            string sInt = UniformInt.GlslType;
            string sDouble = UniformDouble.GlslType;
        }
    }

    public abstract class Uniform<B, T> // Curiously recurring template pattern 
        where B : Uniform<B, T>
    {
        public static string GlslType
        {
            get
            {
                var attribute = typeof(B).GetCustomAttributes(typeof(GlslTypeAttribute), true);

                if (!attribute.Any())
                {
                    throw new InvalidOperationException(
                        "The GslType cannot be determined. Make sure the GslTypeAttribute is added to all derived classes.");
                }

                return ((GlslTypeAttribute)attribute[0]).GlslType;
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    internal sealed class GlslTypeAttribute : Attribute
    {
        public string GlslType { get; private set; }

        public GlslTypeAttribute(string glslType)
        {
            GlslType = glslType;
        }
    }

    [GlslType("int")]
    public class UniformInt : Uniform<UniformInt, int> // Curiously recurring template pattern 
    {
    }

    [GlslType("double")]
    public class UniformDouble : Uniform<UniformDouble, double> // Curiously recurring template pattern 
    {
    }
}

GlslType不是靜態的,因此您需要一個對象引用才能訪問它的值。 抽象類中靜態屬性的主題已經被廣泛涵蓋,即:

解決方案1

將靜態方法添加到返回GlslType所有派生類。 沒有什么需要添加到基類。 可以使用單元測試+反射來檢查缺少的實現。 Wouter de Kort推薦。

解決方案2

更改Uniform<T>以使GlslType靜態:

public abstract class Uniform<T>
{
    public static string GlslType { get { throw new NotImplementedException("Please override with \"new\" in derived class."); } }
    ...
}

UniformInt更改為“覆蓋” GlslType ,保持靜態修飾符:

public class UniformInt : Uniform<int>
{
    public new static string GlslType
    {
        get { return "int"; }
    }
}

填寫??? with null, null

sb.AppendFormat("    {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(null,null), f.Name);

解決方案3

請改用屬性 就像是:

[GlslType("int")]
public class UniformInt : Uniform<int>
{
}

結論

所有這三種解決方案都非常相似,似乎也有相同的缺點(不能強制派生類來實現它)。 通過方法1或2拋出異常將有助於快速找到錯誤,或者通過修改我的fields條件,我可以跳過沒有該屬性的類。

暫無
暫無

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

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