Providing a Read Only List of Classes in C# - c#

I have a set of custom data types that can be used to manipulate basic blocks of data. For example:
MyTypeA Foo = new MyTypeA();
Foo.ParseString(InputString);
if (Foo.Value > 4) return;
Some of these types define read-only properties that describe aspects of the types (for example a name, bit size, etc.).
In my custom framework I want to be able to provide these types to the user for use in their applications but I also want to give the user a list of the available types which they could easily bind to a combobox. My current approach:
public static class DataTypes
{
static ReadOnlyCollection<MyDataType> AvailableTypes;
static DataTypes()
{
List<MyDataType> Types = new List<MyDataType>();
Types.Add(new MyTypeA());
Types.Add(new MyTypeB());
AvailableTypes = new ReadOnlyCollection<MyDataType>(Types);
}
}
What concerns me about this is that the user might obtain a type from the AvailableTypes list (by selecting a combobox item for example) and then use that reference directly rather than creating a clone of the type and using their own reference.
How can I make the list of available types read only so that it doesn't allow any writing or changes to the type instances, forcing the user to create their own clone?
Alternatively is there a better way of providing a list of available types?
Thanks, Andy

Make your custom Type class immutable, same as System.Type and you dont have to worry. A end user can fetch all the data it wants but he can not modify the object in any way.
EDIT: Example of immutable class
Take the following class for instance:
public class ImmutablePerson
{
private readonly string name; //readonly ensures the field can only be set in the object's constructor(s).
private readonly int age;
public ImmutablePerson(string name, int age)
{
this.name = name;
this.age = age;
}
public int Age { get { return this.age; } } //no setter
public string Name { get { return this.name; } }
public ImmutablePerson GrowUp(int years)
{
return new ImmutablePerson(this.name, this.age + years); //does not modify object state, it returns a new object with the new state.
}
}
ImmutablePerson is an immutable class. Once created there is no way a consumer can modify it in any way. Notice that the GrowUp(int years) method does not modify the state of the object at all, it just returns a new instance of ImmutablePerson with the new values.
I hope this helps you understand immutable objects a little better and how they can help you in your particular case.

To get around the problems you've mentioned, you could create a wrapper around your instances, and have the wrapper provide the functionality you require.
For example:
public class TypeDescriptor
{
private MyDataType _dataType;
public TypeDescriptor(MyDataType dataType)
{
_dataType = dataType;
}
public override string ToString()
{
return _dataType.ToString();
}
}
You class would then look something like:
public static class DataTypes
{
public static ReadOnlyCollection<TypeDescriptor> AvailableTypes;
static DataTypes()
{
List<TypeDescriptor> Types = new List<TypeDescriptor>();
Types.Add(new TypeDescriptor(new MyTypeA()));
Types.Add(new TypeDescriptor(new MyTypeB()));
AvailableTypes = new ReadOnlyCollection<TypeDescriptor>(Types);
}
}
Binding to the list and relying on the ToString() will now result in your data types ToString being called.

Create a list of types rather than a list of instances. e.g.
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB()));
etc.
To answer the comment on binding to a drop down list:
MyDropDown.Datasource = Type.Select(t => t.Name);
MyDropDown.DataBind();
This will not use the custom property of your classes but it will give you the simple calss name without all the other guff e.g. MyTypeA

A collection cannot "inject" type modifiers into its members. The collection you have declared is readonly. If you want MyDataType to be readonly you must declare that way.
Somthing like :
EDIT extended class to have a parse method
public class MyDataType
{
private MyDataType()
{
...
}
internal static MyDataType Parse(string someString)
{
MyDataType newOne = new MyDataType();
newOne.Value = ... //int.Parse(someString); ?
}
public int Value { get; private set; }
}
If the collection stays generic there is no readonly constraint.
You would use it like this, following your example.
MyTypeA foo = MyTypeA.Parse(inputString);
if (foo.Value > 4) return;

You probably shouldn't store instances of your types in the list. Instead you can store types. These can be used to create instances:
public static class DataTypes
{
static ReadOnlyCollection<Type> AvailableTypes;
static DataTypes()
{
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB));
AvailableTypes = new ReadOnlyCollection<MyDataType>(Type);
}
}
You can use Activator.CreateInstance to create a concrete instance:
Object myType = Activator.CreateInstance(AvailableTypes[0]);
Unless your types share a common base type you cannot downcast the result and an Object isn't that useful.
Also the use of the term type in your code makes my example a bit confusing as I suggest you store the types of something called type.
You could consider creating and attribute that you then can apply to MyTypeA, MyTypeB etc. Then you can build the AvailableTypes using reflection and the list will always be up to date with your code. E.g. if you add MyTypeC and use the attribute it will automatically be added to the list.
You can also add a display string property to the attribute and use that for display in the combo box. If you want to do that you should store a small object combining the type and the display string in AvailableTypes.
Here is an example. Using generic words like type and data can be confusing so to pick a random name I just use foo. Obviously you should use a more descriptive name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
sealed class FooAttribute : Attribute {
public FooAttribute(String displayName) {
DisplayName = displayName;
}
public String DisplayName { get; private set; }
}
You can decorate you classes using this attribute:
[Foo("Type A")]
class MyTypeA { ... }
[Foo("Type B")]
class MyTypeB { ... }
For the combobox you want a list of factory objects with a nice ToString implementation (this class can be improved by adding some error handling which I have left out to save space):
class FooFactory {
readonly Type type;
public FooFactory(Type type) {
this.type = type;
DisplayName = ((FooAttribute) Attribute.GetCustomAttribute(
type,
typeof(FooAttribute))
).DisplayName;
}
public String DisplayName { get; private set; }
public Object CreateFoo() {
return Activator.CreateInstance(this.type);
}
public override String ToString() {
return DisplayName;
}
}
Returning Object from CreateFoo isn't very useful but that is a separate issue.
You can build this list at run-time:
var factories = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(FooAttribute)))
.Select(t => new FooFactory(t));

I'm not exactly sure of what you want but should something like this be ok ?
public static class DataTypes
{
static Dictionary<string,Type> AvailableTypes
= new Dictionary<string,Type>()
{
{ "MyTypeA", MyTypeA },
{ "MyTypeB", MyTypeB },
...
};
}
That is actually return types instead of sample instances of theses types. Thus you would be sure that only new instances would be created by the user of your class.
Then in the calling code :
MyTypeA a = Activator.CreateInstance(DataTypes.AvailableTypes["MyTypeA"]);

Related

How can I use a base type's methods, which return an object of the base type, in my derived type?

I'm attempting to create a class, ExtendedDataFrame, by inheriting DataFrame from Microsoft.Data.Analysis. The goal is to add a Name property:
using Microsoft.Data.Analysis;
namespace Testing;
public class ExtendedDataFrame : DataFrame
{
public string Name { get; set; } = String.Empty;
public ExtendedDataFrame() : base() { }
public ExtendedDataFrame(string name) : base() => this.Name = name;
// Implement DataFrame's constructors:
public ExtendedDataFrame(string name, params DataFrameColumn[] columns) : base(columns)
{
this.Name = name;
}
public ExtendedDataFrame(string name, IEnumerable<DataFrameColumn> columns) : base(columns)
{
this.Name = name;
}
}
I can build an ExtendedDataFrame:
public class Program
{
public static void Main(string[] args)
{
StringDataFrameColumn col = new("foo", 0);
col.Append("bar");
col.Append("baz");
ExtendedDataFrame edf = new("EDF", col);
...
}
}
But I have lost some functionality. DataFrame has a Clone method. I can use DataFrame's Clone method to create a DataFrame:
// Note: Clone() returns a DataFrame object.
DataFrame df = edf.Clone();
However, if I cannot use DataFrame's Clone method to create an ExtendedDataFrame:
ExtendedDataFrame edf2 = (ExtendedDataFrame)df.Clone();
This results in a System.InvalidCastException: Unable to cast object of type 'Microsoft.Data.Analysis.DataFrame' to type 'DataFrameExtension.ExtendedDataFrame'.
This make sense because Clone is returning a DataFrame object and edf2 is an ExtendedDataFrame.
This brings me to my question. Other than Clone, DataFrame has other methdos (like Filter) that return DataFrame objects. Is there some way I can use those methods with ExtendedDataFrame objects? Or, is there another means of adding a Name property to DataFrame?
It sounds like you’re trying to augment the functionality of ‘DataFrame’ by adding additional stuff (like the Name property) and still use the underlying DataFrame logic like Clone() and Filter(), but you wish to also augment those methods to return instances of ‘ExtendedDataFrame’ instead of ‘DataFrame’.
You might consider a composition approach to give you greater control over your augmented class’s public API. The issue with plain inheritance is you can’t change the return type of Clone(), Filter(), etc. without some smelly workarounds.
Using composition, you take in as a parameter (or create internally) a DataFrame object, and wrap all functionality in your own custom functionality.
Like so:
public class ExtendedDataFrame {
private readonly DataFrame _dataFrame;
public string Name { get; set; }
public ExtendedDataFrame(string name) {
this.Name = name;
this._dataFrame = new DataFrame();
}
protected ExtendedDataFrame(string name, DataFrame dataFrame) {
this.Name = name;
this._dataFrame = dataFrame;
}
public ExtendedDataFrame Clone() {
return new ExtendedDataFrame(this.Name, this._dataFrame.Clone());
}
// Other methods here
}
The caveat is, any DataFrame methods you want to be exposed on your augmented data frame class, you need to manually create methods in your class that call the method on the underlying data frame.

Instantiate a generic list

I want to instantiate a generic list of objects like:
public static class TablesClass
{
private static IList<Tables<T>> TablesInstance { get; set; }
static TablesClass() => Tables = new List<Tables<T>>();
public static void AddTable(Table<t> table) => Tables.Add(table);
}
I can't change Tables<T>, this is a nuget package class.
How may i achieve this? All i have tried just does not work (setting a type T to class, using object instead T and casts - not desired solution).
Can somebody help me?
TablesClass is not a generic class and you are not telling the compiler what type T is supposed to be somewhere.
If you want to be able to add different kinds of objects into the same IList<Tables<T>> list, T must be a common base type for all these objects.
For example, if you want to be able to add apples, pears and bananas to the list, the type parameter T may be specified as Fruit provided that Fruit is the base class for all these types.
Obviously you will need to cast from Fruit if you want to be able to access any member of an item in the list that is specific to a concrete implementation of Fruit class but this is inevitable. You don't throw a bunch of different kinds of fruits into a single basket and expect to be able to always pick up a specific fruit, do you?
Your nuget class must be this style:
public abstract class Tables
{
}
//the Generic class must has a base, by which you can list them
public class Tables<T> : Tables // where T: something base class of your object
{
//...
}
then your class must be:
public static class TablesClass
{
//Search source code of your Nuget package, find its base class of Generic class, the list must be defined as its base
private static IList<Tables> Tables { get; set; }
static TablesClass()
{
Tables = new List<Tables>();
}
public static void AddTable(Tables table)
{
Tables.Add(table);
}
}
then you can use it like this:
public class Test
{
public static void Mains()
{
TablesClass.AddTable(new Tables<A>());
TablesClass.AddTable(new Tables<B>());
TablesClass.AddTable(new Tables<C>());
}
}
If you want to do this kind of thing you need to hold the references using object, but make a method that allows you to store and fetch each table using strong-typing.
Try a class like this:
public class Repository
{
private Dictionary<Type, Dictionary<string, object>> _store
= new Dictionary<Type, Dictionary<string, object>>();
public void Store<T>(string key, T value)
{
if (!_store.ContainsKey(typeof(T)))
{
_store.Add(typeof(T), new Dictionary<string, object>());
}
_store[typeof(T)][key] = value;
}
public T Fetch<T>(string key)
{
return (T)_store[typeof(T)][key];
}
public bool TryFetch<T>(string key, out T value)
{
var success = _store.ContainsKey(typeof(T)) && _store[typeof(T)].ContainsKey(key);
value = success ? this.Fetch<T>(key) : default(T);
return success;
}
public bool TryInject<T>(string key, Action<T> inject)
{
var success = this.TryFetch<T>(key, out T value);
if (success)
{
inject(value);
}
return success;
}
}
Then you can strongly-type the objects into the repository (collection) and strongly-type fetching them out like this:
var repository = new Repository();
repository.Store("a", new TableA());
repository.Store("b", new TableB());
repository.Store("c", new TableC());
repository.Store("d", new TableD());
/* Somewhere else in your code */
TableA a = repository.Fetch<TableA>("a");
TableB b = repository.Fetch<TableB>("b");
TableC c = repository.Fetch<TableC>("c");
TableD d = repository.Fetch<TableD>("d");
The key value (i.e. "a") is optional - you can remove it from the code - but it is useful if you need to store more that one object of a specific type.
Way much simple solution: List<dynamic>.

Get list of property names using interface method

I have two custom types Customer and Employee which implement the interface ITablefy. This interface has only one method, GetPropertyList which returns a list of strings of the property names of the object that implements it. I have a web service which looks like:
public string ReturnPropertyNames(ITablefy i)
{
List<string> propList = new List<string>();
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
propList = table.GetPropertyList(table);
return propList[1];
}
so in this example the Factory creates a concrete type that implements ITablefy
I realized when I had a problem when both of my classes Customer and Employee implemented their GetPropertyList methods exactly the same:
//property list is a private member variable in each class
public List<string> GetPropertyList(ITablefy i)
{
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
foreach (var propInfo in table.GetType().GetProperties())
{
propertyList.Add(propInfo.Name);
}
return propertyList;
}
Rather than copy and paste that code I'm looking for a better solution to what I have currently. If I only want certain types to use the GetPropertyList method how can I control that without having to copy and paste this same code? Harcoding the type to create in each class doesn't seem like a good solution to me. Employee and Customer don't logically make sense to use inheritance either. What's a proper solution for something like this?
factory:
public class TableFactory
{
public ITablefy CreateTable(ITablefy i)
{
if (i is Employee)
{
return new Employee();
}
else if (i is Customer)
{
return new Customer();
}
else
{
return null;
}
}
}
public static List<string> GetPropertyNames(this Object o)
{
List<string> names = new List<string>
foreach (PropertyInfo prop in o.GetType().GetProperties())
names.Add(prop.Name);
return names;
}
Now you can implement ITablefy in terms of any object.GetPropertyNames() using the extension method above.
There are a few questions that comes to my mind:
If It's so easy to do generically, why are you even using the interface?
Shouldn't you be checking properties for public accessors?
Shouldn't your interface be returning a more general type like IEnumerable<string> or ICollection<string>?
Wouldn't the interface be better designed to filter out property names that you don't want? That way you could assume all public properties are part of the set except those that aren't.
You make the interface be something like:
public interface IPropertyInfoFilterProvider {
public Func<PropertyInfo, bool> PropertyInfoSkipFilter { get; set; }
}
or
public interface IPropertyNameFilterProvider {
public Func<string, bool> PropertyNameSkipFilter { get; set; }
}
and then you can initialize the default to (prop) => false.
so now you can harvest the property names automagically and in one place and let implementations determine what gets taken and what doesn't and your harvesting code could use that filter in a linq where clause.
You could make it an extension method on ITablefy.
Or a static method on ITablefy

c# copy constructor generator

I want to copy values from one object to another object. Something similar to pass by value but with assignment.
For example:
PushPin newValPushPin = oldPushPin; //I want to break the reference here.
I was told to write a copy constructor for this. But this class has a lot of properties, it will probably take an hour to write a copy constructor by hand.
Is there a better way to assign an object to another object by value?
If not, is there a copy constructor generator?
Note: ICloneable is not available in Silverlight.
If you can mark the object that is to be cloned as Serializable then you can use in-memory serialization to create a copy. Check the following code, it has the advantage that it will work on other kinds of objects as well and that you don't have to change your copy constructor or copy code each time an property is added, removed or changed:
class Program
{
static void Main(string[] args)
{
var foo = new Foo(10, "test", new Bar("Detail 1"), new Bar("Detail 2"));
var clonedFoo = foo.Clone();
Console.WriteLine("Id {0} Bar count {1}", clonedFoo.Id, clonedFoo.Bars.Count());
}
}
public static class ClonerExtensions
{
public static TObject Clone<TObject>(this TObject toClone)
{
var formatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
formatter.Serialize(memoryStream, toClone);
memoryStream.Position = 0;
return (TObject) formatter.Deserialize(memoryStream);
}
}
}
[Serializable]
public class Foo
{
public int Id { get; private set; }
public string Name { get; private set; }
public IEnumerable<Bar> Bars { get; private set; }
public Foo(int id, string name, params Bar[] bars)
{
Id = id;
Name = name;
Bars = bars;
}
}
[Serializable]
public class Bar
{
public string Detail { get; private set; }
public Bar(string detail)
{
Detail = detail;
}
}
There is a protected member called "MemberwiseClone", you can write this in your class...
public MyClass Clone(){
return (MyClass)this.MemberwiseClone();
}
then you can access..
MyClass newObject = oldObject.Clone();
The only way (that I'm aware of) to do this, and do it correctly, is to implement the copy yourself. Take for example:
public class FrobAndState
{
public Frob Frobber { get; set;}
public bool State { get; set; }
}
public class Frob
{
public List<int> Values { get; private set; }
public Frob(int[] values)
{
Values = new List<int>(values);
}
}
In this example you'd need to know how Frob was implemented, i.e. the fact that you need to call the constructor to create a copy of it as Values is read-only, to be able to make a copy of a given instance of FrobAndState.
Also - you couldn't just implement FrobAndState.Copy thusly:
public class FrobAndState
{
// ... Properties
public FrobAndState Copy()
{
var new = new FrobAndState();
new.State = this.State;
new.Frobber = this.Frobber;
}
}
Because both the instance of FrobAndState that you called .Copy() on, and the new instance would both have a reference to the same instance of Frobber.
In short, copying things is hard and any Copy implementation is difficult to get right.
C# does not have a copy constructor. There are different ways to tackle this. At the OOP level you could use inheritance or aggregation. AutoMapper might also be worth a try.
I want to copy values from one object
to another object. Something similiar
to pass by value but with assignment.
What do you mean by "with assignment"? If you mean that you want people to be able to say:
a = b;
And for you to define what = means, the only way you can do that in C# is if b is a different type to a and you've defined an implicit conversion (or more tenuously, if a stands for something of the form x.Y where Y is a property with a setter). You can't override = for a simple assignment between identical types in C#.
I was told to write a copy constructor
for this. But this class has alot of
properties, it will probably take an
hour to write a copy constructor by
hand.
If that's really true, then I would guess that you have a different problem. Your class is too big.
If you make your class Serializable you could Serialize it to a MemoryStream and Deserialize to a new instance.
If you want copy-on-assignment you should be using a struct instead of a class. But be careful, it is easy to make subtle mistakes. It is highly recommended that all stucts be immmutable to reduce the chance for error.
Though, this may not answer your question directly, but to add a cent; usually the term Clone is linked with shallow copy(referenced objects). To have a deep copy, I believe you will need to look into the some creational pattern(prototype?). The answer to this question might help.
You implement Justin Angel's method of cloning objects in Silverlight
using System;
using System.Reflection;
using System.Windows;
namespace JustinAngelNet.Silverlight.Framework
{
public static class SilverlightExtensions
{
public static T Clone<T>(T source)
{
T cloned = (T) Activator.CreateInstance(source.GetType());
foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())
{
if (curPropInfo.GetGetMethod() != null
&& (curPropInfo.GetSetMethod() != null))
{
// Handle Non-indexer properties
if (curPropInfo.Name != "Item")
{
// get property from source
object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {});
// clone if needed
if (getValue != null && getValue is DependencyObject)
getValue = Clone((DependencyObject) getValue);
// set property on cloned
if (getValue != null)
curPropInfo.GetSetMethod().Invoke(cloned, new object[] {getValue});
}
// handle indexer
else
{
// get count for indexer
int numberofItemInColleciton =
(int)
curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] {});
// run on indexer
for (int i = 0; i < numberofItemInColleciton; i++)
{
// get item through Indexer
object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {i});
// clone if needed
if (getValue != null && getValue is DependencyObject)
getValue = Clone((DependencyObject) getValue);
// add item to collection
curPropInfo.ReflectedType.GetMethod("Add").Invoke(cloned, new object[] {getValue});
}
}
}
}
return cloned;
}
}
}
Then you can do this
MyClass newObject = SilverlightExtensions.Clone(oldObject);

Method for casting generic objects c#

I have a couple of objects that have a corresponding object with identical properties.
class Source1
{
int id;
string name;
DateTime date;
}
class Destination1
{
int id;
string name;
DateTime date;
}
class Source2
{
int id;
string code;
double price;
}
class Destination2
{
int id;
string code;
double price;
}
Now I want to make a method with generic types that can cast an object into his corresponding object.
public TDestination Cast<TSource, TDestination>(TSource source)
{
//TDestination destination = (TDestination) source;
return destination;
}
Your best option here is to introduce a common interface (or base class). There is no other way to cast an item into another.
public interface IItem
{
int id {get;set;}
string name {get;set;}
DateTime date {get;set;}
}
class Source1 : IItem
{
public int id {get;set;}
public string name {get;set;}
public DateTime date {get;set;}
}
class Destination1 : IItem
{
public int id {get;set;}
public string name {get;set;}
public DateTime date {get;set;}
}
You can then just cast the object into the interface and access the properties.
var item1 = (IItem)sourceItem;
var item2 = (IItem)destinationItem;
If you don't want to do that another option would be to using reflection go trough the properties in the source and create a new object of the destination type and try to map properties with shared names. This would however create a new object and is not the same at all as casting. There are libraries such as AutoMapper that can help you with this.
AutoMapper.Mapper.CreateMap<Source1, Destination1>();
var destItem = AutoMapper.Mapper.Map<Destination1 >(sourceItem);
As Magnus points out, if you want to actually cast, interfaces are your way to go. However, I'm thinking you might be actually looking at converting rather then casting.
I would consider checking Automapper as it exists for exactly that.
From the documentation:
var source = new Source<int> { Value = 10 };
var dest = mapper.Map<Source<int>, Destination<int>>(source);
dest.Value.ShouldEqual(10);
You can configure mappings between two types by either naming conventions (even custom naming conventions), custom mappers or a combination of both. The most common use case I have seen for this is mapping a datatransfer object to a model and back again.
If one object is basically the other object with some extra logic and properties the Decorator pattern might be what you are looking for. Here you basically wrap (decorate) one object with some extra stuff and the decorating object links everything through to the original object.
Boris Calens pointed out Automapper, which is great, but if you want to avoid using outside code, a home-made solution for your example problem is pretty simple:
using System.Reflection;
...
TDestination Copy<TSource, TDestination>(TSource source)
where TDestination : new()
{
TDestination dest = new TDestination();
foreach (FieldInfo srcField in typeof(TSource).GetFields())
{
foreach (FieldInfo destField in typeof(TDestination).GetFields())
{
if (destField.Name == srcField.Name && destField.FieldType == srcField.FieldType)
{
destField.SetValue(dest, srcField.GetValue(source));
}
}
}
return dest;
}
You could also easily loop through the properties of the respective types; specify binding flags to filter which fields/properties get copied; and expand the comparison for determining whether the two members are of the same type (i.e. checking whether one type is derived from another).
My answer to this question (which you may also find helpful) shows a similar example, comparing properties and fields.

Categories

Resources