Can I create a List<Class<T>>? - c#

I have a class
public class Setting<T>
{
public string name { get; set; }
public T value { get; set; }
}
now I want to create an IList<Setting<T>> but with different types of Setting<T>'s T in it, I want e.G.
List<Setting<T>> settingsList;
settingsList.Add(new Setting<int>());
settingsList.Add(new Setting<string>());
I've tried IList<Setting<T>> but this seems not possible since the compiler doesn't find Type T.
I know that I could use object but I want it to be strongly typed. So my question is if there is a possibility of getting this working.

Generic types do not have a common type or interface amongst concrete definitions by default.
Have your Setting<T> class implement an interface (or derive from a common class) and create a list of that interface (or class).
public interface ISetting { }
public class Setting<T> : ISetting
{
// ...
}
// example usage:
IList<ISetting> list = new List<ISetting>
{
new Setting<int> { name = "foo", value = 2 },
new Setting<string> { name = "bar", value "baz" },
};

You have to use a common ancestor class for all the class types that you put into the list. If it should be arbitrary types you have to use object for T

You can use T only inside your class:
class Setting<T>
{
// T is defined here
}
not outside. Outside you need to specify the concrete type:
Settings<string> stringSettings = new Settings<string>();
or
List<Settings<string>> list = new List<Settings<string>>();
list.Add(stringSettings);

ye you can do it by using reflection
i wrote such code for another question but you can use this
public abstract class GenericAccess
{
public static IList<T> GetObjectListFromArray<T>(T item)
{
var r = new List<T>();
var obj = typeof(T).Assembly.CreateInstance(typeof(T).FullName);
var p = obj.GetType().GetProperty("Id", System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (p != null)
{
p.SetValue(obj, item, null);
var m = r.GetType().GetMethod("Add");
m.Invoke(r, new object[] { obj });
}
return r;
}
}
and call it like this
IList<int> r = GenericAccess.GetObjectListFromArray<int>(1);

/// <summary>
/// 消息回调委托
/// </summary>
/// <typeparam name="T">TClass</typeparam>
/// <param name="result">返回实体</param>
/// <param name="args">内容包</param>
public delegate void CallbackHandler<in T>(T result, BasicDeliverEventArgs args);
/// <summary>
/// 注册监听程序接口
/// </summary>
public interface IRegistration
{
/// <summary>
/// 路由名称
/// </summary>
string ExchangeName { get; }
/// <summary>
/// 路由Key
/// </summary>
string RouteKey { get; }
/// <summary>
/// 回调操作
/// </summary>
/// <param name="args"></param>
void Call(BasicDeliverEventArgs args);
}
/// <summary>
/// 注册监听程序
/// </summary>
/// <typeparam name="T"></typeparam>
public class Registration<T> : IRegistration where T : class
{
/// <summary>
/// 路由名称
/// </summary>
public string ExchangeName { get; set; }
/// <summary>
/// 路由Key
/// </summary>
public string RouteKey { get; set; }
/// <summary>
/// 消息处理器委托
/// </summary>
public CallbackHandler<T> Handler { get; set; }
/// <summary>
/// 接口回调操作
/// </summary>
/// <param name="args"></param>
public void Call(BasicDeliverEventArgs args)
{
var message = Encoding.UTF8.GetString(args.Body.ToArray());
Handler?.Invoke(JsonConvertHandler.DeserializeObject<T>(message), args);
}
}
/// <summary>
/// 消息监听处理器
/// </summary>
public static class ListenerHandler
{
/// <summary>
/// 单任务锁
/// </summary>
private static readonly object Locker = new object();
/// <summary>
/// 所有注册列表
/// </summary>
public static List<IRegistration> Registrations { get; private set; }
/// <summary>
/// 单例化
/// </summary>
static ListenerHandler()
{
List<ListenerSetting> listeners = MqNoticeHandler.Setting.GetListeners();
MqNoticeHandler.Listener(OnMessage, listeners);
}
/// <summary>
/// 注册监听
/// </summary>
/// <param name="registration"></param>
public static void Register(IRegistration registration)
{
lock (Locker)
Registrations.Add(registration);
}
/// <summary>
/// 解除注册
/// </summary>
/// <param name="registration"></param>
public static void UnRegister(IRegistration registration)
{
lock (Locker)
Registrations.Remove(registration);
}
/// <summary>
/// 获取监听列表
/// </summary>
/// <param name="exchangeName"></param>
/// <param name="routeKey"></param>
/// <returns></returns>
public static IEnumerable<IRegistration> GetRegistrations(string exchangeName, string routeKey)
{
return Registrations.Where(x => x.ExchangeName == exchangeName && x.RouteKey == routeKey);
}
/// <summary>
/// 消息回调处理
/// </summary>
/// <param name="consumer">消费者</param>
/// <param name="args">消息包</param>
/// <returns></returns>
private static MqAckResult OnMessage(EventingBasicConsumer consumer, BasicDeliverEventArgs args)
{
//Example Query and Call
Registrations.First().Call(args);
//Return
return new MqAckResult { Accept = true, ReQueue = false };
}
}

Related

Deserializing received Json-Rpc data via Websocket API

I'm trying to figure out a way to create a generic Websocket JsonRpc client.
After connecting I'm starting a loop to listen for data coming from the WebSocket API and sending that data to the event as a string. I'd like to return a generic JsonRpcResponse<T> object instead but not sure how or if it's possible.
Where JsonRpcResponse has an Id and Method fields as defined in the spec and T is a specific type depending on the data received.
From what I've seen there's no way to use generics here since I'd have to call another event with a non-generic type or object to pass that data along.
public event Func<string, Task>? OnDataReceived;
public async Task ConnectAsync()
{
Uri uri = new Uri(_url);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(3000);
await _client.ConnectAsync(uri, cancellationTokenSource.Token);
// Start listening for data
await Task.Factory.StartNew(async () =>
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
while (_client.State == WebSocketState.Open && !cancellationTokenSource.IsCancellationRequested)
{
var receivedData = await ReadStringAsync(cancellationTokenSource.Token);
if (OnDataReceived != null)
{
await OnDataReceived.Invoke(receivedData);
}
}
};
}
How about this:
namespace GenericJsonResponse {
/// <summary>
/// Desired returned type
/// </summary>
/// <typeparam name="T"></typeparam>
public class JsonResponse<T> {
public T? Data { get; set; }
public int Id { get; set; } = 0;
public string Method { get; set; } = string.Empty;
/// <summary>
/// Convert string to anew instance
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
/// <remarks>will have to add to each sub class</remarks>
public static T FromJson(string json) {
throw new NotImplementedException();
}
}
/// <summary>
/// Generic socket listener / sub class per type
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericSocketListener<T> {
/// <summary>
/// exposes event with generic response
/// </summary>
public event Func<string, Task<JsonResponse<T>>>? OnDataReceived;
/// <summary>
/// Listen to socket
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public virtual async Task Listen( CancellationToken token) {
string data = string.Empty;
while (! token.IsCancellationRequested) {
// listen... and get typed result, save string to data
JsonResponse<T> result = await OnDataReceived.Invoke(data);
}
}
}
/// <summary>
/// Dummy poco
/// </summary>
public class Person {
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
}
/// <summary>
/// Class that will listen to people
/// </summary>
public class PersonSocketListener : GenericSocketListener<Person> {
}
}

Rhino mock stub error

I am new to Mock testing and i have created a Unit Test using RhinoMock.
First stub is running proper but second is throwing Null Exception, code is as below.
[TestMethod]
public void TestMethod1()
{
SetUp(); //bind List ftsController and ftsEreceiptNumberPrefix
MockRepository mocks = new MockRepository();
var ftsUnitOfWork = mocks.StrictMock<IFtsUnitOfWork>();
ftsUnitOfWork.Stub(x => x.Repository<FtsController>().Get()).Return(ftsController.AsQueryable());
ftsUnitOfWork.Stub(x =>
{
if (x.Repository<FtsPrefix>() == null)
{
throw new ArgumentNullException("Input cannot be null");
}
x.Repository<FtsPrefix>().Get();
}).Return(ftsPrefix.AsQueryable());
;
BoGeneratePrefix generateEreceiptPrefix = new BoGeneratePrefix (logger,ftsUnitOfWork);
generatePrefix.ProcessJob(null);
}
ProcessJob :
public class BoGeneratePrefix : IBoDataPurging
{
#region private Variables
private readonly ILogger _logger;
private readonly IUnitOfWork _ftsUnitOfWork;
private readonly string _defaultTraceCategory;
#endregion
#region BoGeneratePrefix Constructor
/// <summary>
/// Initialized class oject BoGeneratePrefix
/// </summary>
/// <param name="logger"></param>
/// <param name="ftsUoW"></param>
public BoGeneratePrefix(ILogger logger, IFtsUnitOfWork ftsUoW)
{
_defaultTraceCategory = GetType().Name;
_logger = logger;
_ftsUnitOfWork = ftsUoW;
}
public void ProcessJob(Configuration hconfiguration)
{
try
{
var lstController = _ftsUnitOfWork.Repository<FtsController>().Get().Select(x => x. Id).Distinct().AsNoTracking();
foreach (var Id in lstController.ToList())
{
var prefix = _ftsUnitOfWork.Repository<FtsPrefix>()
.Get(x => x. Id == Id
&& x.Status == Constants.NotPrefix).Count();
var ignoreForLowerSafePoint =
_ftsUnitOfWork.Repository<ConfigurationParameter>()
.Get(y => y.ParamType == Constants.IgnoreForLowerSafePoint &&
y.ParamName == Id)
.AsNoTracking()
.Select(t => t.ParamValues).SingleOrDefault();
var currentTime = DateTime.ParseExact(DateTime.Now.ToString(Constants.HHmmssTime),
Constants.HHmmssTime,
System.Globalization.CultureInfo.InvariantCulture).TimeOfDay;
if ( !( hconfiguration.StartTime <= currentTime
&& hconfiguration.EndTime >= currentTime))
{
return;
}
}
}
catch (Exception ex)
{
throw;
}
}
repository :
public interface IRepository<TEntity> : IDisposable where TEntity : class
{
/// <summary>
/// Delete the record from the database by accepting the input parameter as id
/// </summary>
/// <param name="id">Parameter id is used to delete record from the database</param>
void Delete(object id);
/// <summary>
/// Delete the enity
/// </summary>
/// <param name="entityToDelete"></param>
void Delete(TEntity entityToDelete);
/// <summary>
/// Get Queryable by passing the Expression
/// </summary>
/// <param name="filter">this is used for filter parameter/Expression of query</param>
/// <param name="orderBy">Passing condition of orderBy for query</param>
/// <param name="includeProperties">Properties to be included in to the query while generating the query on filter/order by</param>
/// <returns>Entity type Queryable i.e. creates query depend upon accepted entity type as input parameter</returns>
#pragma warning disable S2360
IQueryable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
#pragma warning restore S2360
/// <summary>
/// Get Queryable by accepting the input parameter as modifiedSinceTimestamp
/// </summary>
/// <param name="modifiedSinceTimestamp"> modifiedSinceTimestamp </param>
/// <returns></returns>
IQueryable<TEntity> GetModifiedSince(long modifiedSinceTimestamp);
/// <summary>
/// Provides information of an entity by accepting the input parameters
/// </summary>
/// <param name="id">it gives the enity on the id condition </param>
/// <returns>Returns Entity </returns>
TEntity GetById(params object[] id);
/// <summary>
/// Inserts all changes made in this context as a Focus business transaction and enlists it for data insertion.
/// </summary>
/// <param name="entity">Entity i.e. object of generic type </param>
void Insert(TEntity entity);
/// <summary>
/// Gives information about which entity to update
/// </summary>
/// <param name="entityToUpdate">information about to update an enity</param>
void Update(TEntity entityToUpdate);
/// <summary>
///
/// </summary>
/// <param name="query"></param>
/// <param name="parameters"></param>
/// <returns></returns>
IEnumerable<TEntity> ExecWithStoreProcedure(string query, params object[] parameters);
/// <summary>
///
/// </summary>
/// <param name="entityToUpdate"></param>
void Detach(TEntity entityToUpdate);
}
UnitofWork -
public class FtsUnitOfWork : IFtsUnitOfWork
{
#region local variables
private readonly ILogger _logger;
private IFtsDbProvider _ftsDbProvider;
private readonly string _defaultTraceCategory;
private DbContext _context;
private Hashtable _repositories;
#endregion local variables
/// <summary>
/// Constructor for Fts Unit Of Work
/// </summary>
/// <param name="logger"></param>
/// <param name="ftsDbProvider"></param>
public FtsUnitOfWork(ILogger logger, IFtsDbProvider ftsDbProvider)
{
_defaultTraceCategory = GetType().Name;
_logger = logger;
_logger.WriteTrace("FtsUnitOfWork: Initializing", _defaultTraceCategory);
_ftsDbProvider = ftsDbProvider;
_context = new FtsDbContext(_logger, "FtsDbStore", _ftsDbProvider.GetFtsDbCompiledModel());
_logger.WriteTrace("FtsUnitOfWork: Initialized", _defaultTraceCategory);
}
/// <summary>
/// Saves all changes made in this context as a Focus business transaction and enlists it for data consolidation.
/// </summary>
/// <returns></returns>
public virtual int Save()
{
try
{
return _context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
throw new Exception("Optimistic_Concurrency_Check");
}
}
/// <summary>
///
/// </summary>
/// <param name="focusDtTransactionId"></param>
/// <returns></returns>
public int Save(Guid focusDtTransactionId)
{
return _context.SaveChanges();
}
/// <summary>
/// Generic Repository this function creates the Repository by accepting the parameter as Entity type
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IRepository<T> Repository<T>() where T : class
{
if (_repositories == null)
{
_repositories = new Hashtable();
}
var type = typeof(T).Name;
if (!_repositories.ContainsKey(type))
{
var repositoryType = typeof(Repository<>);
var repositoryInstance =
Activator.CreateInstance(repositoryType
.MakeGenericType(typeof(T)), _context);
_repositories.Add(type, repositoryInstance);
}
return (IRepository<T>)_repositories[type];
}
/// <summary>
///
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <param name="sqlParameters"></param>
/// <param name="spName"></param>
/// <returns></returns>
public List<T1> GetMany<T1>(SqlParameter[] sqlParameters, string spName)
{
return _context.Database.SqlQuery<T1>(spName, sqlParameters).ToList();
}
/// <summary>
///
/// </summary>
/// <param name="isolationLevel"></param>
/// <returns></returns>
public DbContextTransaction GetDbContextTransaction(IsolationLevel isolationLevel)
{
return _context.Database.BeginTransaction(isolationLevel);
}
#region IDisposable Support
private bool _disposedValue; // To detect redundant calls
/// <summary>
///
/// </summary>
/// <param name="disposing"></param>
public virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_logger.WriteTrace("FtsUnitOfWork: Disposing", _defaultTraceCategory);
_ftsDbProvider = null;
_repositories = null;
this._context.Dispose();
this._context = null;
_logger.WriteTrace("FtsUnitOfWork: Disposed", _defaultTraceCategory);
}
_disposedValue = true;
}
}
/// <summary>
///
/// </summary>
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
If i commented out first stub then second stub work properly otherwise throws below error :
An exception of type 'System.ArgumentNullException' occurred in Fts.Services.Housekeeping.Tests.dll but was not handled in user code
Additional information: Value cannot be null.

Synchronising a collection over a websocket connection

I'm working on a client-server system at the moment, and I'm trying to get a collection to synchronise across a websocket. Everything is in C# + .Net 4.5, and I was wondering if there was a particular best practise for synchronising data over a websocket. It's a one way sync:
Server: BindingCollection< MyClass > ----- Websocket -----> Client: BindingCollection< MyClass >
The collection could be up to 1000 objects with 20 fields each so sending the whole lot each time seems a little wasteful.
I would use a observer pattern and only send the changed object to be synced.
So I finally took the time to write a small example.
I am using a in-memory generic repository that invokes events on changes. The changes is then sent to all clients so that you do not have to send the complete list/collection.
A simple model to monitor
using System;
namespace SynchronizingCollection.Common.Model
{
public class MyModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
A Generic Repository
Notice the event OnChange that is called when something is added/updated/removed. The event is "subscribed" to in a XSockets long running controller (a singleton) See the "RepoMonitor" class
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace SynchronizingCollection.Server.Repository
{
/// <summary>
/// A static generic thread-safe repository for in-memory storage
/// </summary>
/// <typeparam name="TK">Key Type</typeparam>
/// <typeparam name="T">Value Type</typeparam>
public static class Repository<TK, T>
{
/// <summary>
/// When something changes
/// </summary>
public static event EventHandler<OnChangedArgs<TK,T>> OnChange;
private static ConcurrentDictionary<TK, T> Container { get; set; }
static Repository()
{
Container = new ConcurrentDictionary<TK, T>();
}
/// <summary>
/// Adds or updates the entity T with key TK
/// </summary>
/// <param name="key"></param>
/// <param name="entity"></param>
/// <returns></returns>
public static T AddOrUpdate(TK key, T entity)
{
var obj = Container.AddOrUpdate(key, entity, (s, o) => entity);
if(OnChange != null)
OnChange.Invoke(null,new OnChangedArgs<TK, T>(){Key = key,Value = entity, Operation = Operation.AddUpdate});
return obj;
}
/// <summary>
/// Removes the entity T with key TK
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Remove(TK key)
{
T entity;
var result = Container.TryRemove(key, out entity);
if (result)
{
if (OnChange != null)
OnChange.Invoke(null, new OnChangedArgs<TK, T>() { Key = key, Value = entity, Operation = Operation.Remove});
}
return result;
}
/// <summary>
/// Removes all entities matching the expression f
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static int Remove(Func<T, bool> f)
{
return FindWithKeys(f).Count(o => Remove(o.Key));
}
/// <summary>
/// Find all entities T matching the expression f
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static IEnumerable<T> Find(Func<T, bool> f)
{
return Container.Values.Where(f);
}
/// <summary>
/// Find all entities T matching the expression f and returns a Dictionary TK,T
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static IDictionary<TK, T> FindWithKeys(Func<T, bool> f)
{
var y = from x in Container
where f.Invoke(x.Value)
select x;
return y.ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// Returns all entities as a Dictionary TK,T
/// </summary>
/// <returns></returns>
public static IDictionary<TK, T> GetAllWithKeys()
{
return Container;
}
/// <summary>
/// Returns all entities T from the repository
/// </summary>
/// <returns></returns>
public static IEnumerable<T> GetAll()
{
return Container.Values;
}
/// <summary>
/// Get a single entity T with the key TK
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static T GetById(TK key)
{
return Container.ContainsKey(key) ? Container[key] : default(T);
}
/// <summary>
/// Get a single entity T as a KeyValuePair TK,T with the key TK
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static KeyValuePair<TK, T> GetByIdWithKey(TK key)
{
return Container.ContainsKey(key) ? new KeyValuePair<TK, T>(key, Container[key]) : new KeyValuePair<TK, T>(key, default(T));
}
/// <summary>
/// Checks if the repository has a key TK
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool ContainsKey(TK key)
{
return Container.ContainsKey(key);
}
}
}
Event argument and an enum to know what change just happend
using System;
namespace SynchronizingCollection.Server.Repository
{
/// <summary>
/// To send changes in the repo
/// </summary>
/// <typeparam name="TK"></typeparam>
/// <typeparam name="T"></typeparam>
public class OnChangedArgs<TK,T> : EventArgs
{
public Operation Operation { get; set; }
public TK Key { get; set; }
public T Value { get; set; }
}
}
namespace SynchronizingCollection.Server.Repository
{
/// <summary>
/// What kind of change was performed
/// </summary>
public enum Operation
{
AddUpdate,
Remove
}
}
The Controller that send changes to the clients...
using System;
using SynchronizingCollection.Common.Model;
using SynchronizingCollection.Server.Repository;
using XSockets.Core.XSocket;
using XSockets.Core.XSocket.Helpers;
using XSockets.Plugin.Framework;
using XSockets.Plugin.Framework.Attributes;
namespace SynchronizingCollection.Server
{
/// <summary>
/// Long running controller that will send information to clients about the collection changes
/// </summary>
[XSocketMetadata(PluginRange = PluginRange.Internal, PluginAlias = "RepoMonitor")]
public class RepositoryMonitor : XSocketController
{
public RepositoryMonitor()
{
Repository<Guid, MyModel>.OnChange += RepositoryOnChanged;
}
private void RepositoryOnChanged(object sender, OnChangedArgs<Guid, MyModel> e)
{
switch (e.Operation)
{
case Operation.Remove:
this.InvokeTo<Demo>(p => p.SendUpdates, e.Value,"removed");
break;
case Operation.AddUpdate:
this.InvokeTo<Demo>(p => p.SendUpdates, e.Value, "addorupdated");
break;
}
}
}
}
The XSockets controller that clients call to add/remove/update the collection.
using System;
using SynchronizingCollection.Common.Model;
using SynchronizingCollection.Server.Repository;
using XSockets.Core.XSocket;
namespace SynchronizingCollection.Server
{
public class Demo : XSocketController
{
public bool SendUpdates { get; set; }
public Demo()
{
//By default all clients get updates
SendUpdates = true;
}
public void AddOrUpdateModel(MyModel model)
{
Repository<Guid, MyModel>.AddOrUpdate(model.Id, model);
}
public void RemoveModel(MyModel model)
{
Repository<Guid, MyModel>.Remove(model.Id);
}
}
}
And a demo client in C# that adds and removed 10 different objects... But it would be easy to use the JavaScript API as well. Especially with knockoutjs for manipulating the collection on the client.
using System;
using System.Threading;
using SynchronizingCollection.Common.Model;
using XSockets.Client40;
namespace SynchronizingCollection.Client
{
class Program
{
static void Main(string[] args)
{
var c = new XSocketClient("ws://127.0.0.1:4502","http://localhost","demo");
c.Controller("demo").OnOpen += (sender, connectArgs) => Console.WriteLine("Demo OPEN");
c.Controller("demo").On<MyModel>("addorupdated", model => Console.WriteLine("Updated " + model.Name));
c.Controller("demo").On<MyModel>("removed", model => Console.WriteLine("Removed " + model.Name));
c.Open();
for (var i = 0; i < 10; i++)
{
var m = new MyModel() {Id = Guid.NewGuid(), Name = "Person Nr" + i, Age = i};
c.Controller("demo").Invoke("AddOrUpdateModel", m);
Thread.Sleep(2000);
c.Controller("demo").Invoke("RemoveModel", m);
Thread.Sleep(2000);
}
Console.ReadLine();
}
}
}
You can download the project from my dropbox: https://www.dropbox.com/s/5ljbedovx6ufkww/SynchronizingCollection.zip?dl=0
Regards
Uffe

Get the exact type as property in C# class

Sorry for the general title but it's a bit hard to explain in few words what is my problem currently.
So I have a simple class factory like this:
public Model Construct<T>(T param) where T : IModelable
{
new Model {Resource = param};
return n;
}
The Model class looks like this:
public class Model
{
public object Resource { get; set; }
}
The problem is, that you can see, is the Resource is currently an object. And I would like that Resource should be the type, what is get from the Construct and not lost the type-safe...
I tried to solve it with type parameter but it fails, because I can extend Model class with type parameter but what if I would like to store it to a simple class repository?
Then Construct will work, but if I would like to get the instanced class from the repository, I have to declare the type paramter again like:
Repository.Get<Model<Spaceship>>(0) .... and of course it's wrong because I would like that Model itself knows, what type of Resource has been added in Construct.
Does anybody any idea how to handle this?
The whole code currently look like this:
/// <summary>
/// Class Repository
/// </summary>
public sealed class Repository
{
/// <summary>
/// The _lock
/// </summary>
private static readonly object _lock = new object();
/// <summary>
/// The _syncroot
/// </summary>
private static readonly object _syncroot = new object();
/// <summary>
/// The _instance
/// </summary>
private static volatile Repository _instance;
/// <summary>
/// The _dict
/// </summary>
private static readonly Dictionary<int, object> _dict
= new Dictionary<int, object>();
/// <summary>
/// Prevents a default data of the <see cref="Repository" /> class from being created.
/// </summary>
private Repository()
{
}
/// <summary>
/// Gets the items.
/// </summary>
/// <value>The items.</value>
public static Repository Data
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null) _instance = new Repository();
}
}
return _instance;
}
}
/// <summary>
/// Allocates the specified id.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="parameter">The parameter.</param>
/// <resource name="id">The id.</resource>
/// <resource name="parameter">The parameter.</resource>
public void Allocate(int id, object parameter)
{
lock (_syncroot)
{
_dict.Add(id, parameter);
}
}
/// <summary>
/// Gets the specified id.
/// </summary>
/// <typeparam name="T">The type of the tref.</typeparam>
/// <param name="id">The id.</param>
/// <returns>``0.</returns>
/// <resource name="id">The id.</resource>
public T Get<T>(int id)
{
lock (_syncroot)
{
return (T) _dict[id];
}
}
}
/// <summary>
/// Class IModelFactory
/// </summary>
public sealed class ModelFactory
{
/// <summary>
/// The _lock
/// </summary>
private static readonly object _lock = new object();
/// <summary>
/// The _instance
/// </summary>
private static volatile ModelFactory _instance;
/// <summary>
/// Prevents a default instance of the <see cref="ModelFactory" /> class from being created.
/// </summary>
private ModelFactory()
{
}
/// <summary>
/// Gets the data.
/// </summary>
/// <value>The data.</value>
public static ModelFactory Data
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null) _instance = new ModelFactory();
}
}
return _instance;
}
}
/// <summary>
/// Constructs the specified param.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="param">The param.</param>
/// <returns>Model{``0}.</returns>
public Model Construct<T>(T param) where T : IModelable
{
var n = new Model {Resource = param};
return n;
}
}
/// <summary>
/// Class Model
/// </summary>
/// <typeparam name="T"></typeparam>
public class Model
{
public object Resource { get; set; }
}
/// <summary>
/// Interface IModelable
/// </summary>
public interface IModelable
{
/// <summary>
/// Gets or sets the mass.
/// </summary>
/// <value>The mass.</value>
float Mass { get; set; }
}
/// <summary>
/// Class spaceship
/// </summary>
public class Spaceship : IModelable
{
/// <summary>
/// Gets or sets the mass.
/// </summary>
/// <value>The mass.</value>
public float Mass { get; set; }
}
So the problem will be lighted here:
Add to the Repository:
Repository.Data.Allocate(1, ModelFactory.Data.Construct(new Spaceship()));
It's okay, but after:
var test_variable = Repository.Data.Get<Model>(1);
So now I have a non type-safe object from a type parameter, I don't know, that what type of class has been stored with the c model construction.
I'm very thankful for the suggestions of using type paramter on the Model class as well, but than it will come up another problem, because I have to change the Get function with it:
var test_variable = Repository.Data.Get<Model<Spaceship>>(1);
But that's definitely wrong, because I won't know, that what kind of type of class has been stored in the model..., so I would like to achieve to avoid this type parameter definition when I would like to load the instance from the Repository.
You can solve this by making your Model class generic, like this:
public class Model<T>
{
public T Resource { get; set; }
}
Then, your Construct method could work like this:
public Model<T> Construct<T>(T param) where T : IModelable<T>
{
return new Model<T>() {Resource = param};
}
You probably need a generic type in the model class:
public class Model<T>
{
public T Resource { get; set; }
}
This sort of structure is one approach you could take:
public Model<T> Construct<T>(T param) where T : IModelable
{
var n = new Model<T> {Resource = param};
return n;
}
public class Model<T> : IModel<T> where T : IModelable
{
public T Resource { get; set; }
}
public interface IModel<out T> where T : IModelable
{
T Resource { get; }
}
This covariant interface allows you to refer to the types more generically where you wish, in the same way that you can pass an IEnumerable<string> into something expecting an IEnumerable<object>.
IModel<Spaceship> shipModel = // whatever
IModel<IModelable> model = shipModel;
//or even:
List<Model<Spaceship>> shipModels = // whatever
IEnumerable<IModel<IModelable>> models = shipModels;

Strange issue using PropertyInfo in C#

I have a class like so:
public class CompanyData
{
# region Properties
/// <summary>
/// string CompanyNumber
/// </summary>
private string strCompanyNumber;
/// <summary>
/// string CompanyName
/// </summary>
private string strCompanyName;
[Info("companynumber")]
public string CompanyNumber
{
get
{
return this.strCompanyNumber;
}
set
{
this.strCompanyNumber = value;
}
}
/// <summary>
/// Gets or sets CompanyName
/// </summary>
[Info("companyName")]
public string CompanyName
{
get
{
return this.strCompanyName;
}
set
{
this.strCompanyName = value;
}
}
/// <summary>
/// Initializes a new instance of the CompanyData class
/// </summary>
public CompanyData()
{
}
/// <summary>
/// Initializes a new instance of the CompanyData class
/// </summary>
/// <param name="other"> object company data</param>
public CompanyData(CompanyData other)
{
this.Init(other);
}
/// <summary>
/// sets the Company data attributes
/// </summary>
/// <param name="other">object company data</param>
protected void Init(CompanyData other)
{
this.CompanyNumber = other.CompanyNumber;
this.CompanyName = other.CompanyName;
}
/// <summary>
/// Getting array of entity properties
/// </summary>
/// <returns>An array of PropertyInformation</returns>
public PropertyInfo[] GetEntityProperties()
{
PropertyInfo[] thisPropertyInfo;
thisPropertyInfo = this.GetType().GetProperties();
return thisPropertyInfo;
}
}
A csv file is read and a collection of CompanyData objects is created
In this method I am trying to get properties and values:
private void GetPropertiesAndValues(List<CompanyData> resList)
{
foreach (CompanyData resRow in resList)
{
this.getProperties = resRow.ExternalSyncEntity.GetEntityProperties();
this.getValues = resRow.ExternalSyncEntity.GetEntityValue(resRow.ExternalSyncEntity);
}
}
Here's the problem, for the first object the GetEntityProperties() returns the CompanyNumber as the first element in the array. For the remaining objects it returns CompanyName as the first element.
Why is the sequence not consistent?
Regards.
The Type.GetProperties() does not return ordered result.
The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies.
If you want to use ordered/consistent result, it is better to sort the returned array.

Categories