I'm creating a table from a dynamically created IBindingList using
class TableBuilder
{
private Type m_TableType;
// ... create and define m_TableType here
public IBindingList CreateTable()
{
return Activator.CreateInstance(m_TableType) as IBindingList;
}
}
class DynamicTable : IBindingList
{
private IBindingList m_theList;
private TableBuilder m_tableBuilder;
public DynamicTable(TableBuilder tableBuilder)
{
m_tableBuilder = tableBuilder;
m_theList = tableBuilder.CreateTable();
}
public void LoadData()
{
// ...
}
}
I would like to promote the IBindingList functionality of m_theList to the level of the class so I can make calls like
var myTable = new DynamicTable(someTableBuilder);
int count = myTable.Count;
myTable.LoadData();
count = myTable.Count;
How can I get all the m_theList public members to be members of DynamicTable. I can not derive DynamicTable from m_TableType since it is only known at run time.
-Max
You will have to do it as old subclassing, implement the interface and in each method call the corresponding method in m_theList:
//methods
public void AddIndex(PropertyDescriptor property)
{
m_theList.AddIndex(property);
}
public object AddNew()
{
return m_theList.AddNew();
}
//properties
public bool AllowEdit
{
get { return m_theList.AllowEdit; }
}
....
//for events you can use add/remove syntax
public event ListChangedEventHandler ListChanged
{
add { m_theList.ListChanged += value; }
remove { m_theList.ListChanged -= value; }
}
....
//indexer...
public object this[int index]
{
get
{
return m_theList[index];
}
set
{
m_theList[index] = value;
}
}
Related
I have 2 classes Folder and File. They have a property NumberFiles. For File, it's of course only 1 at all case, for Folder, it depends how many files in the folder. This property must implement RaisePropertyChanged to bind.
I don't allow a set NumberFiles in FileRecord. But I can't find a solution, so this is my hack. With this code, I can set NumberFiles, but it doesn't have any effect.
public abstract class Record : ViewModelBase
{
private int _numberFiles;
public virtual int NumberFiles
{
get
{
return _numberFiles;
}
set
{
_numberFiles= value;
RaisePropertyChanged(nameof(NumberFiles));
}
}
//and a lot of properties
}
public class FolderRecord : Record
{
//and a lot of properties
}
public class FileRecord : Record
{
public override int NumberFiles
{
get
{
return 1;
}
set
{
//HACK : let empty SET
}
}
//and a lot of properties
}
public Main()
{
var list = new List<Record>(); // this list used to bind to the DataGrid
Record rc;
for (some condition)
{
if (folder)
{
rc = new RecordFolder();
rc.NumberFiles = 10; // OK
}
else if (file)
{
rc = new FileRecord();
rc.NumberFiles = 10; // the property NumberFiles can't allow a set, should compile error here
}
list.Add(rc);
}
}
I already have tried like put protected set in the base class but I can't set the value later.
public abstract class Record
{
public abstract int GetNumberFiles();
}
public class FolderRecord : Record
{
private int _numberOfFiles;
public void SetNumberOfFiles(int numberOfFiles)
{
_numberOfFiles = numberOfFiles;
}
public override int GetNumberFiles()
{
return _numberOfFiles;
}
}
public class FileRecord : Record
{
public override int GetNumberFiles()
{
return 1;
}
}
public class RegistrationManager
{
public List<object> RegisteredObjects;
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
I want that RegisterObjects be accessible from outside of the class, but also that the only way to populate the RegisterObjects list is through TryRegisterObject(object o).
Is this possible ?
I would hide it under ReadonlyCollection. In this case client won't be able to add elements via casting to IList for example. It totaly depends on how secure you want to be (in simplest scenario exposing IEnumerable will be pretty enough).
public class RegistrationManager
{
private List<object> _registeredObjects;
ReadOnlyCollection<object> _readOnlyRegisteredObjects;
public RegistrationManager()
{
_registeredObjects=new List<object>();
_readOnlyRegisteredObjects=new ReadOnlyCollection<object>(_registeredObjects);
}
public IEnumerable<object> RegisteredObjects
{
get { return _readOnlyRegisteredObjects; }
}
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
Hide it under IEnumerable. You'll get "readonly" collection outise the class and work with List inside:
public class RegistrationManager
{
public IEnumerable<object> RegisteredObjects
{
get
{
return _registeredObjects;
}
}
private List<object> _registeredObjects;
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
More protected variant with IReadOnlyColection:
public class RegistrationManager
{
public IReadOnlyCollection<object> RegisteredObjects
{
get { return new ReadOnlyCollection<object>(_registeredObjects); }
}
private List<object> _registeredObjects;
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
Something like that (I guess you have to have read-only access which means that Add, RemoveAt, Clear etc. are not allowed):
public class RegistrationManager
{
// change RegisteredObjects to be private
//TODO: do you really want List<object> instead of, say, List<RegisteredItem>?
private List<object> RegisteredObjects = new List<object>();
// let RegisteredObjects be visible as read-only
public IReadOnlyList<object> Items {
get {
return RegisteredObjects;
}
}
// your TryRegisterObject
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
downside of the solution is that, technically, it's possible to cast back, e.g.
RegistrationManager manager = ...
// you can't do this
// manager.Items.Add(new Object()); // <- compile time error
// but can do this
((List<Object>) (manager.Items)).Add(new Object());
return it as IReadOnlyList
public class RegistrationManager
{
private List<object> _registeredObjects;
public IReadOnlyList<object> RegisteredObjects
{
get{ return _registeredObjects; }
}
public bool TryRegisterObject(object o)
{
// ...
// Add or not to Registered
// ...
}
}
Yes you can expose a property of type IReadOnlyCollection(T).
List(T) implements IReadonlyCollection(T)
public class RegistrationManager
{
private List<object> _registeredObjects;
public IReadOnlyCollection<object> RegisteredObjects
{
get
{
return _registeredObjects as IReadOnlyCollection<object>;
}
}
}
I have an interface
using ClassAbstractFactory;
public interface IPlugin
{
AbstractFactory GetFactory();
}
and an AbstractFactory
public abstract class AbstractFactory
{
public abstract AbstractCake CreateCake();
public abstract AbstractBox CreateBox();
}
public abstract class AbstractCake
{
public abstract void Interact(AbstractBox box);
}
public abstract class AbstractBox
{
}
and I have .dll that inherit AbstractCake
public class ChocolateCake : AbstractCake
{
private bool _isPacked;
private bool _isDecorated;
private string _nameOfCake;
public ChocolateCake()
{
_isPacked = false;
_isDecorated = false;
_nameOfCake = "Шоколадный";
}
public bool IsPacked
{
get { return _isPacked; }
}
public bool IsDecorated
{
get { return _isDecorated; }
}
public string NameOfCake { get; set; }
public override void Interact(AbstractBox box)
{
_isPacked = true;
}
}
I load dll like this:
public IPlugin LoadAssembly(string assemblyPath)
{
Assembly ptrAssembly = Assembly.LoadFile(assemblyPath);
foreach (Type item in ptrAssembly.GetTypes())
{
if (!item.IsClass) continue;
if (item.GetInterfaces().Contains(typeof(IPlugin)))
{
return (IPlugin)Activator.CreateInstance(item);
}
}
throw new Exception("Invalid DLL, Interface not found!");
}
List<IPlugin> list = new List<IPlugin>();
foreach (var assemblyPath in GetPathsListToDll())
{
list.Add(LoadAssembly(assemblyPath));
}
How can I acess to attributes in my ChocolateCake,to use them like
foreach (var str in list)
{
Boolean a = str.GetFactory().GetCake().CreateCake().IsPacked;
}
or like this
string a = str.GetFactory().GetCake().CreateCake().NameOfCake;
or like this
str.GetFactory().GetCake().CreateCake().NameOfCake("Something");
or like this
str.GetFactory().GetCake().CreateCake().IsDecorated(true);
The problem here is that the AbstractFactory has a method that returns AbstractCake, and AbstractCake itself has no properties at all. As it stands, you would need to downcast the Cake (direct, or with the as keyword) to a ChocolateCake prior to accessing any of its properties, which is really messy:
string a = (ChocolateCake)(str.GetFactory().CreateCake()).NameOfCake;
Here are some considerations:
Move the properties which are common to all types of cake into AbstractCake, e.g. NameOfCake, IsPacked and IsDecorated
Given that the AbstractFactory and AbstractCake classes do not have any implementation at all, consider changing these to interfaces instead of abstract classes, i.e. ICakeFactory and ICake. Concrete implementations will be ChocolateCakeFactory and ChocolateCake as before.
Consumers of the factory and the cake should now only access what is exposed on the interfaces (ICakeFactory, ICake and IBox), and not need to do any down casting or make any assumptions about the actual concrete type of Cake etc.
i.e.
public interface ICake
{
void Interact(IBox box);
bool IsPacked { get; }
bool IsDecorated { get; }
string NameOfCake { get; set; }
}
public class ChocolateCake : ICake
{
private bool _isPacked;
private bool _isDecorated;
private string _nameOfCake;
public ChocolateCake() // ctor is not on the interface and is implementation detail
{
_isPacked = false;
_isDecorated = false;
_nameOfCake = "Шоколадный";
}
public void Interact(IBox box) {...}
public bool IsPacked { get { return _isPacked; } }
public bool IsDecorated { get { return _isDecorated; } }
// ...
}
public interface ICakeFactory
{
ICake CreateCake();
IBox CreateBox();
}
public class ChocolateCakeFactory : ICakeFactory
{
public ICake CreateCake() {return new ChocolateCake();}
public IBox CreateBox() {return new ChocolateCakeBox();}
}
Re : Usage
It is highly unlikely that you would ever do this:
string a = str.GetFactory().GetCake().CreateCake().NameOfCake;
str.GetFactory().GetCake().CreateCake().NameOfCake = "Something"; // Prop setter
as this would create a new cake instance each time (and discard the instance). How about:
class Bakery
{
private readonly ICakeFactory _cakeFactory;
public Bakery(ICakeFactory cakeFactory)
{
Contract.Requires(cakeFactory != null);
cakeFactory = _cakeFactory;
}
bool BakeStuff()
{
var cake = _cakeFactory.CreateCake();
cake.NameOfCake = "StackOverflow";
return cake.IsDecorated && cake.IsPacked;
}
}
Edit, Re Raise change Events
This involves implementing INotifyPropertyChanged
public interface ICake : INotifyPropertyChanged
Which you can then raise on your mutable properties, e.g.
public string NameOfCake
{
get { return _nameOfCake} ;
set {
var propChanged = PropertyChanged;
if (propChanged != null && value != _nameOfCake)
{
propChanged(this, new PropertyChangedEventArgs("NameOfCake"));
}
_nameOfCake = value;
}
}
And subscribe like so
var cake = new ChocolateCake();
cake.PropertyChanged += (sender, eventArgs)
=> Console.WriteLine("Property {0} has changed", eventArgs.PropertyName);
Would this work?
public abstract class AbstractFactory
{
public abstract TCake CreateCake<TCake>() where TCake : AbstractCake, new();
public abstract AbstractBox CreateBox();
}
...
var cake = str.GetFactory().CreateCake<ChocolateCake>();
I've got problem using generics. I'm creating an interface called IProblem, where each problem has results (answers) and a result (if it is correct)
public interface IProblem<T>
{
ushort ResultCount { get; }
T[] Results { get; }
bool IsCorrect();
}
public abstract class ProblemBase<T> : IProblem<T>
{
private T[] _results;
private ushort? _resultCount;
public ushort ResultCount
{
get
{
if (_resultCount == null) throw new ArgumentNullException("_resultCount");
return (ushort)_resultCount;
}
protected set
{
if (_resultCount != value)
_resultCount = value;
}
}
public T[] Results
{
get
{
if (_results == null)
_results = new T[ResultCount];
return _results;
}
}
public abstract bool IsCorrect();
}
This is an example where I create an arithmetic problem, called ProblemA. T is decimal because the array datatype should be decimal (anothers problems maybe might have string, or int)
public class ProblemA: ProblemBase<decimal>
{
private decimal _number1;
private decimal _number2;
private Operators _operator;
public decimal Number1
{
get { return _number1; }
set { _number1 = value; }
}
public decimal Number2
{
get { return _number2; }
set { _number2 = value; }
}
public Operators Operator
{
get { return _operator; }
set { _operator = value; }
}
public decimal Result
{
get { return Results[0]; }
set { Results[0] = value; }
}
public ProblemA()
{
this.ResultCount = 1;
}
public override bool IsCorrect()
{
bool result;
switch (_operator)
{
case Operators.Addition:
result = this.Result == (this.Number1 + this.Number2);
break;
case Operators.Subtract:
result = this.Result == (this.Number1 - this.Number2);
break;
case Operators.Multiplication:
result = this.Result == (this.Number1 * this.Number2);
break;
case Operators.Division:
result = this.Result == (this.Number1 / this.Number2);
break;
default:
throw new ArgumentException("_operator");
}
return result;
}
}
I'm using MVVM, so I'd like to have a ViewModel for each problem where contains ProblemBase<T> as property, but how it's a generic, I guess it will be a problem if a put in IProblemViewModel as generic.
public interface IProblemViewModel : IViewModel
{
ProblemBase<T> Problem { get; set; }
}
I said this because later a plan to use a ObservableCollection<IProblemViewModel>, so I'm not sure if there's no problem if I write IProblemViewModel or IProblemViewModel<T>.
Thanks in advance.
Maybe I haven't understood this perfectly, but is this what you are after?
ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
{
new ProblemViewModel<DerivedResult>(),
new ProblemViewModel<OtherResult>()
};
This can be achieved by declaring the generic argument as covariant.
You could also change the collection to
ObservableCollection<IProblem<BaseType>>
and just have it accept a specific result chain. In this example, DerivedResult and OtherResult must then inherit from BaseType to fit into the collection.
The big caveat is that primitive types don't fit into this hierarchy, in any way. You will have to wrap them in IProblem<IntResult> and so on.
Of course, you could implement a simple carrier, for example Boxer which would box any value type instead of implementing one for each type.
One last caveat: It's not possible to have a 'set' property on a covariant type, so IProblemViewModel can only support get.
A complete, compilable example:
class Program
{
public interface IProblem<out T>
{
ushort ResultCount { get; }
T[] Results { get; }
bool IsCorrect();
}
public class ProblemBase<T> : IProblem<T>
{
private T[] _results;
private ushort? _resultCount;
public ushort ResultCount
{
get
{
if (_resultCount == null) throw new ArgumentNullException("_resultCount");
return (ushort)_resultCount;
}
protected set
{
if (_resultCount != value)
_resultCount = value;
}
}
public T[] Results
{
get
{
if (_results == null)
_results = new T[ResultCount];
return _results;
}
}
public bool IsCorrect()
{
return true;
}
}
public interface IProblemViewModel<out T>
{
IProblem<T> Problem { get; }
}
public class BaseResult
{
}
public class DerivedResult : BaseResult
{
}
public class OtherResult : BaseResult
{
}
public class ProblemViewModel<T> : IProblemViewModel<T>
{
public IProblem<T> Problem
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
static void Main(string[] args)
{
ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
{
new ProblemViewModel<DerivedResult>(),
new ProblemViewModel<OtherResult>()
//, new ProblemViewModel<int>() // This is not possible, does not compile.
};
}
}
Your view model interface could be defined like this:
public interface IProblemViewModel<T> : IViewModel
{
//No reason to use the base here instead of the interface
IProblem<T> Problem { get; set; }
}
I'm not sure if you are planning on binding the Problem to an interface in WPF or Silverlight, but if you are make sure that Problem also implements INotifyPropertyChanged. Binding to non Dependency Properties on objects that don't implement INotifyPropertyChanged causes the a memory leak where the object will never be released. You can find more info on the leak here: http://support.microsoft.com/kb/938416
EDIT: Added answer to comment.
You are correct that having IProblemViewModel<T> would stop you using it in an ObservableCollection if you intend to show more than one type of <T>. However since when you are binding it doesn't really matter what the objects type is when you bind to it why not just make the collection an ObservableCollection<IViewModel>?
I need to refactor the following class:
public interface IEmployee
{
int VacationWeeks { get; }
int YearsWithCompany { set; get; }
double Salary { set; get; }
}
public class Employee : IEmployee
{
private readonly int vacationWeeks;
public Employee(int vacationWeeks)
{
this.vacationWeeks = vacationWeeks;
}
public int VacationWeeks
{
get { return vacationWeeks; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
I need to make sure that VacationWeeks depends only on YearsWithCompany, and I am loading the mapping from the database. So far I have come up with this:
public class EmployeeNew : IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
public EmployeeNew(Dictionary<int, int> vacationWeeksTable)
{
this.vacationWeeksTable = vacationWeeksTable;
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
This class implements what I want, but it still has one vulnerability: different instances of EmployeeNew in the same collection may have been created with different instances of vacationWeeksTable.
All instances of EmployeeNew in the same collection must refer to the same vacationWeeksTable.
The application I am refactoring uses lots of List all over the system, and we need to be able to modify YearsWithCompany and Salary, yet to guarantee that only one vacationWeeksTable is used per List. These lists are iterated several times; its elements are modified in each iteration.
Here is my imperfect solution. Suggestions are welcome:
// this class does two things, which I do not like
public class EmployeeList : IEnumerable<IEmployee>, IEmployee
{
private Dictionary<int, int> vacationWeeksTable;
private List<EmployeeSpecificData> employees;
private int currentIndex;
private EmployeeSpecificData CurrentEmployee
{
get { return employees[currentIndex]; }
}
public IEnumerator<IEmployee> GetEnumerator()
{
for (currentIndex = 0; currentIndex < employees.Count; currentIndex++)
{
yield return this;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
// this is ugly repetitive code I don't like
public int YearsWithCompany
{
get { return CurrentEmployee.YearsWithCompany; }
set { CurrentEmployee.YearsWithCompany = value; }
}
// this is ugly repetitive code I don't like
public double Salary
{
get { return CurrentEmployee.Salary; }
set { CurrentEmployee.Salary = value; }
}
}
I use the following to create and init some of the classes that need default and shared behaviour. Maybe if you can refactor it will help:
It is some form of the Factory and FlyWeight patterns combined (the flyweight part can be removed in your scenario), which in addition has a concept of class Type shared handlers.
I simplified and removed some stuff that you wont need but there is more to remove, I added comments.
Usage would be: (app init)
Dictionary<int,int> vacationWeeksTable = new Dictionary<int,int>();
// fill the table
Factory<Employee>.Init(vacationWeeksTable);
The whenever you create a Employee class:
// remove grouping in the factory class to remove this null
Employee em = Factory<Employee>.Create(null);
It takes only a WeakReference to the classes so you don't have to worry about GC.
Each employee will have the shared vacationWeeksTable setup on creation, without the possibility to change it after from outside if not using the factory class.
You could change the vacation table for all running instances of Employee at any moment in the runtime of the app with:
// this will call the method registered for SetInitialdata on all instances of Employee classes.
// again remove grouping to remove that null
Factory<Employee>.Call(EventHandlerTypes.SetInitialData, null, vacTable);
Sample implementation of Employee:
class Employee : IBaseClass
{
private Dictionary<int, int> vacationWeeksTable;
public virtual void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> register)
{
group = 0; // disable different groups
register(new Key<Employee, int>(0), group, EventHandlerTypes.SetInitialData, SetVacationWeeksTable);
}
public virtual void RegisterSharedData(Action<IKey, object> regData)
{
// remove this from factory and interface, you probably dont need it
// I have been using it as a FlyWeight data store for classes.
}
private void SetVacationWeeksTable(object sender, SharedEventArgs e)
{
vacationWeeksTable = e.GetData<Dictionary<int, int>>();
}
}
Code pattern Implementation:
IBaseClass : interface that each of my classes that are creatable through a factory implement
public enum EventHandlerTypes
{
SetInitialData // you can add additional shared handlers here and Factory<C>.Call - it.
}
public class SharedEventArgs : EventArgs
{
private object data;
public SharedEventArgs(object data)
{
this.data = data;
}
public T GetData<T>()
{
return (T)data;
}
}
public interface IBaseClass
{
void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> regEvent);
void RegisterSharedData(Action<IKey, object> regData);
}
Utility generic classes:
public interface IKey
{
Type GetKeyType();
V GetValue<V>();
}
public class Key<T, V> : IKey
{
public V ID { get; set; }
public Key(V id)
{
ID = id;
}
public Type GetKeyType()
{
return typeof(T);
}
public Tp GetValue<Tp>()
{
return (Tp)(object)ID;
}
}
public class Triple<T, V, Z>
{
public T First { get; set; }
public V Second { get; set; }
public Z Third { get; set; }
public Triple(T first, V second, Z third)
{
First = first;
Second = second;
Third = third;
}
}
Factory class with slight modification to handle your scenario:
public static class Factory<C> where C : IBaseClass, new()
{
private static object initialData;
private static Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>> handlers = new Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>>();
private static Dictionary<IKey, object> data = new Dictionary<IKey, object>();
static Factory()
{
C newClass = new C();
newClass.RegisterSharedData(registerSharedData);
}
public static void Init<IT>(IT initData)
{
initialData = initData;
}
public static Dt[] GetData<Dt>()
{
var dataList = from d in data where d.Key.GetKeyType() == typeof(Dt) select d.Value;
return dataList.Cast<Dt>().ToArray();
}
private static void registerSharedData(IKey key, object value)
{
data.Add(key, value);
}
public static C Create(int? group)
{
C newClass = new C();
newClass.RegisterSharedHandlers(group, registerSharedHandlers);
// this is a bit bad here since it will call it on all instances
// it would be better if you can call this from outside after creating all the classes
Factory<C>.Call(EventHandlerTypes.SetInitialData, null, initialData);
return newClass;
}
private static void registerSharedHandlers(IKey subscriber, int? group, EventHandlerTypes type, Action<object, SharedEventArgs> handler)
{
handlers.Add(subscriber, new Triple<EventHandlerTypes, int, WeakReference>(type, group ?? -1, new WeakReference(handler)));
}
public static void Call<N>(EventHandlerTypes type, int? group, N data)
{
Call<N>(null, type, group, data);
}
public static void Call<N>(object sender, EventHandlerTypes type, int? group, N data)
{
lock (handlers)
{
var invalid = from h in handlers where h.Value.Third.Target == null select h.Key;
// delete expired references
foreach (var inv in invalid.ToList()) handlers.Remove(inv);
var events = from h in handlers where h.Value.First == type && (!#group.HasValue || h.Value.Second == (int)#group) select h.Value.Third;
foreach (var ev in events.ToList())
{
// call the handler
((Action<object, SharedEventArgs>)ev.Target)(sender, arg);
}
}
}
}
Make a class which contains a Dictionary. Creating or getting instance of this new class will load the dictionary in a consistent way. Then your BOs can take an instance of the class, thus ensuring they're all using the same data (because the class containingthe list knows how to load itself with the proper set of data).