связать строку с классом, чтобы я мог получить строку, если класс задан как параметр общего типа - PullRequest
0 голосов
/ 05 декабря 2018

Для разных классов мне нужно прикрепить строку к классу (т.е. Class1 имеет строку hello, Class2 содержит строку world и т. Д.).Тогда у меня будет параметр общего типа T где-нибудь, который будет (во время выполнения) одним из этих классов.Мне нужно иметь возможность извлечь связанную строку из этого параметра универсального типа.

Как мне настроить это и заставить его работать?

Поскольку все классы написаныя могу использовать любой возможный подход (например, определить общий интерфейс для них или общий базовый класс или любой другой).

Я попытался создать базовый класс, который имеет открытое статическое поле, содержащее строку, и для каждого фактическогоКласс "перезаписать" (скрыть базу и создать новую) строку.Но оказалось, что я все еще не могу получить строку, когда есть только параметр типа T.

public class BaseClass 
{ 
    public static string Get => ""; 
}

public class Class1 : BaseClass 
{ 
    public static new string Get => "hello"; 
} 

public class Class2 : BaseClass 
{ 
    public static new string Get => "world"; 
}

public class Testing<T> where T : BaseClass
{
    public void Test()
    {
        string s = T.Get;
        // compiler error: "'T' is a type parameter, which is not valid in the given context"
        // strangely though, BaseClass.Get and Class1.Get and Class2.Get work fine!
    }
}

Реальный вариант использования:

У меня есть статический классMySerializer<T>, который должен десериализовать объекты типа T.Во время десериализации я хочу проверить, соответствует ли мой объект типа T схеме, связанной с типом T.

. Для проверки мне нужно сначала добавить схему.Для каждого класса T, который можно десериализовать, существует своя схема, которую я храню в своем проекте как встроенный ресурс, поэтому у каждой схемы есть путь (например, путь к файлу).Это означает: для каждого класса T мне нужно связать строку (путь) с классом, чтобы я мог получить этот путь из T.

Вот соответствующая часть моегоСериализатор и процесс добавления схемы:

public static class MySerializer<T>
{
    private static readonly XmlSerializer _mySerializer = new XmlSerializer(typeof(T));
    private static readonly XmlReaderSettings _settings = new Func<XmlReaderSettings>(() =>
    {
        System.Reflection.Assembly assy = typeof(MySerializer<T>).Assembly;
        XmlSchemaSet schemas = new XmlSchemaSet();
        schemas.Add(null,
            XmlReader.Create(assy.GetManifestResourceStream(T.GetAssociatedString())));
            // T.GetAssociatedString(): How to make this work?
        return new XmlReaderSettings
        {
            Schemas = schemas,
            ValidationType = ValidationType.Schema,
            ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings |
                XmlSchemaValidationFlags.ProcessIdentityConstraints
        };
    })();

    public static T Deserialize(Stream strm)
    {
        using (XmlReader reader = XmlReader.Create(strm, _settings))
        {
            return (T)_mySerializer.Deserialize(reader);
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Поскольку статические методы и параметры универсального типа не работают вместе в C # (спасибо Мэтью Уотсону за ссылку на блог Эрика Липпета), и я не хочу создавать новый экземпляр T исключительно для возможности вызоваметод, я пойду с атрибутами.

[AttributeUsage(AttributeTargets.Class)]
class SomeStringAttribute : Attribute
{
    public string SomeString { get; set; }

    public SomeStringAttribute(string s)
    {
        SomeString = s;
    }
}

[SomeString("hello")]
public class Class1
{ 
} 

[SomeString("world")]
public class Class2
{ 
}

public class Testing<T>
{
    public void Test()
    {
        string s =
            ((SomeStringAttribute)typeof(T).GetCustomAttributes(typeof(SomeStringAttribute),
                false)[0]).SomeString;
    }
}
0 голосов
/ 05 декабря 2018

Вы могли бы использовать отражение, чтобы сделать это, но учтите, что все свойства должны быть статическими (в приведенном выше примере кода вводятся нестатические свойства для производного класса).

Воткомпилируемый пример:

using System;

namespace Demo
{
    public class BaseClass
    {
        public static string Get => "";
    }

    public class Class1 : BaseClass
    {
        public new static string Get => "hello";
    }

    public class Class2 : BaseClass
    {
        public new static string Get => "world";
    }

    public class Testing<T> where T : BaseClass
    {
        public string Test()
        {
            var property = typeof(T).GetProperty("Get");

            if (property != null)
                return (string) property.GetValue(null, null);

            return null;
        }
    }

    class Program
    {
        static void Main()
        {
            var test1 = new Testing<Class1>();
            Console.WriteLine(test1.Test());  // Prints "hello"

            var test2 = new Testing<Class2>();
            Console.WriteLine(test2.Test()); // Prints "world"
        }
    }
}

В этом коде where T : BaseClass на самом деле не требуется для его компиляции и работы, но вы можете оставить его, чтобы было ясно, что он должен толькоиспользоваться с классами, которые наследуются от BaseClass.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...