Бросок к универсальному типу в C#

В iOS 11 стало действительно легко закруглять углы. Код ниже округляет верхний левый и нижний правый углы.

myView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]
38
задан 16 June 2009 в 19:48
поделиться

8 ответов

Это работает для вас?

interface IMessage
{
    void Process(object source);
}

class LoginMessage : IMessage
{
    public void Process(object source)
    {
    }
}

abstract class MessageProcessor
{
    public abstract void ProcessMessage(object source, object type);
}

class MessageProcessor<T> : MessageProcessor where T: IMessage
{
    public override void ProcessMessage(object source, object o) 
    {
        if (!(o is T)) {
            throw new NotImplementedException();
        }
        ProcessMessage(source, (T)o);
    }

    public void ProcessMessage(object source, T type)
    {
        type.Process(source);
    }
}


class Program
{
    static void Main(string[] args)
    {
        Dictionary<Type, MessageProcessor> messageProcessors = new Dictionary<Type, MessageProcessor>();
        messageProcessors.Add(typeof(string), new MessageProcessor<LoginMessage>());
        LoginMessage message = new LoginMessage();
        Type key = message.GetType();
        MessageProcessor processor = messageProcessors[key];
        object source = null;
        processor.ProcessMessage(source, message);
    }
}

Это дает вам правильный объект. Единственное, в чем я не уверен, - это то, достаточно ли в вашем случае иметь его в качестве абстрактного MessageProcessor.

Edit: Я добавил интерфейс IMessage. Фактический код обработки теперь должен стать частью различных классов сообщений, которые должны реализовывать этот интерфейс.

30
ответ дан 27 November 2019 в 03:18
поделиться
Type type = typeof(MessageProcessor<>).MakeGenericType(key);

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

РЕДАКТИРОВАТЬ: Я должен уточнить. Я перешел с типа var на тип типа. Я хочу сказать, что теперь вы можете сделать что-то вроде этого:

object obj = Activator.CreateInstance(type);

obj теперь будет правильным типом, но, поскольку вы не знаете, какой тип «ключ» находится во время компиляции, нет возможности преобразовать его и сделать что-нибудь полезное. с ним.

9
ответ дан 27 November 2019 в 03:18
поделиться

You can't do that. You could try telling your problem from a more high level point of view (i.e. what exactly do you want to accomplish with the casted variable) for a different solution.

You could go with something like this:

 public abstract class Message { 
     // ...
 }
 public class Message<T> : Message {
 }

 public abstract class MessageProcessor {
     public abstract void ProcessMessage(Message msg);
 }
 public class SayMessageProcessor : MessageProcessor {
     public override void ProcessMessage(Message msg) {
         ProcessMessage((Message<Say>)msg);
     }
     public void ProcessMessage(Message<Say> msg) {
         // do the actual processing
     }
 }

 // Dispatcher logic:
 Dictionary<Type, MessageProcessor> messageProcessors = {
    { typeof(Say), new SayMessageProcessor() },
    { typeof(string), new StringMessageProcessor() }
 }; // properly initialized

 messageProcessors[msg.GetType().GetGenericArguments()[0]].ProcessMessage(msg);
4
ответ дан 27 November 2019 в 03:18
поделиться

Вы можете написать метод, который принимает тип как универсальный параметр:

void GenericProcessMessage<T>(T message)
{
    MessageProcessor<T> processor = messageProcessors[typeof(T)]
        as MessageProcessor<T>;

    //  Call method processor or whatever you need to do
}

Затем вам нужен способ вызвать метод с правильным универсальным аргументом. Вы можете сделать это с помощью отражения:

public void ProcessMessage(object message)
{
    Type messageType = message.GetType();
    MethodInfo method = this.GetType().GetMethod("GenericProcessMessage");
    MethodInfo closedMethod = method.MakeGenericMethod(messageType);
    closedMethod.Invoke(this, new object[] {message});
}
8
ответ дан 27 November 2019 в 03:18
поделиться

Это просто недопустимо:

Type key = message.GetType();
MessageProcessor<key> processor = messageProcessors[key] as MessageProcessor<key>;

Вы не можете получить универсальный тип в качестве значения переменной.

Вам придется сделать переключатель или что-то в этом роде:

Type key = message.GetType();
if (key == typeof(Foo))
{
    MessageProcessor<Foo> processor = (MessageProcessor<Foo>)messageProcessors[key];
    // Do stuff with processor
}
else if (key == typeof(Bar))
{
    MessageProcessor<bar> processor = (MessageProcessor<Bar>)messageProcessors[key];
    // Do stuff with processor
}
...
3
ответ дан 27 November 2019 в 03:18
поделиться

Как уже упоминалось, вы не можете разыграть его напрямую. Одно из возможных решений - унаследовать эти универсальные типы от неуниверсального интерфейса, и в этом случае вы все равно можете вызывать на нем методы без отражения. Используя отражение, вы можете передать сопоставленный объект любому ожидающему его методу, тогда приведение будет выполнено за вас. Итак, если у вас есть метод под названием Accept, ожидающий MessageProcessor в качестве параметра, затем его можно будет найти и вызвать динамически.

1
ответ дан 27 November 2019 в 03:18
поделиться

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

interface IMessage
{
}

class LoginMessage : IMessage
{
}

class LogoutMessage : IMessage
{
}

class UnknownMessage : IMessage
{
}

interface IMessageProcessor
{
    void PrcessMessageBase(IMessage msg);
}

abstract class MessageProcessor<T> : IMessageProcessor where T : IMessage
{
    public void PrcessMessageBase(IMessage msg)
    {
        ProcessMessage((T)msg);
    }

    public abstract void ProcessMessage(T msg);

}

class LoginMessageProcessor : MessageProcessor<LoginMessage>
{
    public override void ProcessMessage(LoginMessage msg)
    {
        System.Console.WriteLine("Handled by LoginMsgProcessor");
    }
}

class LogoutMessageProcessor : MessageProcessor<LogoutMessage>
{
    public override void ProcessMessage(LogoutMessage msg)
    {
        System.Console.WriteLine("Handled by LogoutMsgProcessor");
    }
}

class MessageProcessorTest
{
    /// <summary>
    /// IMessage Type and the IMessageProcessor which would process that type.
    /// It can be further optimized by keeping IMessage type hashcode
    /// </summary>
    private Dictionary<Type, IMessageProcessor> msgProcessors = 
                                new Dictionary<Type, IMessageProcessor>();
    bool processorsLoaded = false;

    public void EnsureProcessorsLoaded()
    {
        if(!processorsLoaded)
        {
            var processors =
                from processorType in Assembly.GetExecutingAssembly().GetTypes()
                where processorType.IsClass && !processorType.IsAbstract &&
                      processorType.GetInterface(typeof(IMessageProcessor).Name) != null
                select Activator.CreateInstance(processorType);

            foreach (IMessageProcessor msgProcessor in processors)
            {
                MethodInfo processMethod = msgProcessor.GetType().GetMethod("ProcessMessage");
                msgProcessors.Add(processMethod.GetParameters()[0].ParameterType, msgProcessor);
            }

            processorsLoaded = true;
        }
    }

    public void ProcessMessages()
    {
        List<IMessage> msgList = new List<IMessage>();
        msgList.Add(new LoginMessage());
        msgList.Add(new LogoutMessage());
        msgList.Add(new UnknownMessage());

        foreach (IMessage msg in msgList)
        {
            ProcessMessage(msg);
        }
    }

    public void ProcessMessage(IMessage msg)
    {
        EnsureProcessorsLoaded();
        IMessageProcessor msgProcessor = null;
        if(msgProcessors.TryGetValue(msg.GetType(), out msgProcessor))
        {
            msgProcessor.PrcessMessageBase(msg);
        }
        else
        {
            System.Console.WriteLine("Processor not found");
        }
    }

    public static void Test()
    {
        new MessageProcessorTest().ProcessMessages();
    }
}
5
ответ дан 27 November 2019 в 03:18
поделиться

У меня возникла похожая проблема. У меня есть класс;

Action<T>

который имеет свойство типа T.

Как мне получить свойство, если я не знаю T? Я не могу привести к Action<>, пока не знаю T.

РЕШЕНИЕ:

Реализуйте негенеративный интерфейс;

public interface IGetGenericTypeInstance
{
    object GenericTypeInstance();
}

Теперь я могу привести объект к IGetGenericTypeInstance и GenericTypeInstance вернет свойство как тип object.

8
ответ дан 27 November 2019 в 03:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: