#c#
#c#
Вопрос:
Я пришел из мира JavaScript / TypeScript и немного изучаю C #, просто для удовольствия. В настоящее время я пытаюсь сделать то, что я очень привык делать в JS, то есть иметь полезную нагрузку, которая может изменяться в соответствии с переменной внутри класса. Итак, я попробовал следующее:
namespace Shared.Commands
{
public class Command
{
public string clientUuid { get; set; }
public string type { get; set; }
public dynamic payload { get; set; }
}
}
Итак, в этом примере я хочу знать, какой тип payload
основан на type
. Мне было интересно, какие будут альтернативы использованию dynamic
в этом случае, поскольку я просматривал некоторые статьи, и в них упоминается, что мне следует избегать использования dynamic
как можно больше.
Дело в том, что я не знаю, как реализовать это любым другим способом, и хотел бы получить некоторые рекомендации. Я был бы очень признателен за любые советы или примеры.
Комментарии:
1. Когда вы узнаете, какой тип payloud вы получите? изменится ли это в течение срока службы экземпляра команды?
2. Если вы знаете тип при создании команды, вы можете использовать learn.microsoft.com/de-de/dotnet/csharp/programming-guide /…
3. Тип берется из десериализатора, и его тип не должен меняться в течение срока службы экземпляра команды.
4. Единственная информация, которая говорит мне, какого типа будет полезная нагрузка, — это строка, имя
type
которой находится внутри объекта command5.
Payload<T> Payload { get; set; }
должно сработать … но мне также было бы любопытно, как будут выглядеть некоторые полезные нагрузки. Дополнительные мысли, JS допускает множество вещей, которые, даже если их можно взломать в серверной части, являются плохой практикой.
Ответ №1:
Простым способом сделать это было бы определить полезную нагрузку как объект, а затем использовать сериализацию. Существует множество сериализаторов, поэтому выберите тот, который лучше всего подходит для вас.
public class Command
{
public string ClientUuid { get; set; }
public string Type { get; set; }
public Object Payload { get; set; }
public static void Serialize ( Command command, MemoryStream stream )
{
var formatter = new BinaryFormatter ();
formatter.Serialize ( stream, command );
}
public static void Deserialize (out Command command, MemoryStream stream )
{
var formatter = new BinaryFormatter();
command = (Command)formatter.Deserialize ( stream );
}
}
Тогда, если ввод текста важен, вы могли бы сделать что-то вроде этого.
public class Command<T> : Command
{
public new T Payload
{
get
{
return (T)base.Payload;
}
set
{
base.Payload = (T)value;
}
}
}
и используйте это так.
public void Usage ()
{
Command<YourObject> obj = new Command<YourObject> () {
Payload = new YourObject ()
};
using ( var stream = new MemoryStream () )
{
Command.Serialize ( obj, stream );
// do something with serialized data in stream;
}
}
Комментарии:
1. Все решения отлично работают. Я использовал сочетание каждого из них и придумал свое решение. Определение
Command
иCommand<T>
вместе сnew T Payload
было настоящим трюком. Все сработало, у меня есть не только что-то достаточно общее, но и типизированное. Приветствия!
Ответ №2:
Это слишком долго и подробно для комментария, но я считаю, что это направление, в котором вы движетесь, поэтому я его напечатаю.
Сначала определения классов и интерфейсов:
public interface ICommand
{
string ClientUuid { get; set; }
Type Type { get; }
object Payload { get; set; }
}
public class Command<T> : ICommand
{
public string ClientUuid { get; set; }
public Type Type
{
get
{
return Payload.GetType();
}
}
public object Payload { get; set; }
}
public class Person
{
public string Name {get; set;}
public string Address { get; set; }
public override string ToString()
{
return Name " is at " Address;
}
}
Выше наш интерфейс показывает, как должен выглядеть объект, если это «команда».
Наша команда использует преимущества дженериков: теоретически она любого типа.
«Человек» — это пользовательская полезная нагрузка.
В использовании C #:
List<ICommand> commands = new List<ICommand>()
{
new Command<int>()
{
ClientUuid = "a-uuid",
Payload = 15
},
new Command<string>()
{
ClientUuid = "a-uuid",
Payload = "we has string"
},
new Command<Person>()
{
ClientUuid = "A person UUID",
Payload = new Person()
{
Name = "Tom",
Address = "123 Main St"
}
}
};
Я создаю список ICommand с различными типами.
Если мы хотим увидеть значения, которые мы можем сделать:
foreach(ICommand command in commands)
{
Console.WriteLine(command.Type);
Console.WriteLine(command.Payload.ToString());
}
который будет регистрировать:
System.Int32
15
System.String
we has string
Person
Tom is at 123 Main St
Я хотел, чтобы этот длинный пример продемонстрировал пару вещей.
- Вы можете заставить классы контролировать большую часть вашей логики. И подобная логика
if (obj.Type == 'MyType')
не является строго необходимой. - Мы все еще можем воспользоваться преимуществами ввода и запрошенной вами логики:
Пример:
if (command.Type == typeof(Person))
{
// Do things, with the stuff
}
Ответ №3:
Есть несколько способов сделать это
- Шаблон команды
Я узнал об этом шаблоне в книге Head First Design Patterns: http://umass-cs-220.github.io/weeks/04/08-command.pdf
Основная идея заключается в том, что вы создаете ICommand интерфейса, который определяет функцию выполнения. Классы, которые реализуют интерфейс ICommand, имеют поле частной полезной нагрузки, и execute знает, как работать с данными частной полезной нагрузки. Намного чище, но требует от вас переосмысления вашего дизайна.
- Отражение Используйте метод Type, чтобы получить тип объекта и выполнить преобразование объекта полезной нагрузки в нужный вам тип. Не так чисто, как шаблон команды, но, возможно, проще для понимания.
Пример:
namespace MyStackExchangeExamplesConsole
{
public class Command
{
public string clientUuid { get; set; }
public object payload { get; set; }
}
class Program
{
static void Main(string[] args)
{
var command1 = new Command()
{
clientUuid = "UUID1",
payload = new string("I am a string")
};
var command2 = new Command()
{
clientUuid = "UUID2",
payload = (double)5.0
};
DoSomethingWithTheCommand(command1);
DoSomethingWithTheCommand(command2);
}
static void DoSomethingWithTheCommand(Command cmd)
{
if (cmd.payload is string)
{
var s = (string)cmd.payload;
Console.WriteLine($"I'm a string ! {s}");
}
else if (cmd.payload is double)
{
var d = (double)cmd.payload;
Console.WriteLine($"I'm a double ! {d}");
}
}
}
}