How to properly implement a generic method? - c#

Can someone help me figure out how to implement this method generically? The compiler complains that it cannot resolve t.Id. Which makes sense but, how do I tell it that all objects that pass will have an Id property. Here is the interface I defined for T:
namespace LiveWire.Model
{
public interface ILiveWireModel
{
Guid Id { get; }
}
}
The interface for all repositories:
internal interface ILiveWireRepository<T>
{
ICacheProvider Cache { get; }
string CacheKey { get; }
SqlConnection CreateConnection();
IEnumerable<T> GetData<TD>();
IEnumerable<T> LoadData<TD>();
Dictionary<Guid, T> GetCachedData<TD>();
void ClearCache();
}
And my method:
public IEnumerable<T> GetData<TD>()
where TD : ILiveWireModel
{
var data = GetCachedData<TD>();
if (data == null)
{
data = LoadData<TD>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}
I'm including the whole class here which I hope will clear some things up.
internal abstract class LiveWireRepositoryBase<T> : ILiveWireRepository<T>
{
public ICacheProvider Cache { get; private set; }
public string CacheKey { get; private set; }
internal LiveWireRepositoryBase()
{
Cache = new DefaultCacheProvider();
}
public SqlConnection CreateConnection()
{
return new SqlConnection(
ConfigurationManager
.ConnectionStrings["LiveWire4Database"]
.ConnectionString);
}
public IEnumerable<T> GetData<TD>()
where TD : ILiveWireModel
{
var data = GetCachedData<TD>();
if (data == null)
{
data = LoadData<TD>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}
public IEnumerable<T> LoadData<TD>()
{
return new List<T>();
}
public Dictionary<Guid, T> GetCachedData<TD>()
{
throw new NotImplementedException();
}
public void ClearCache()
{
throw new NotImplementedException();
}
}
I'm getting this error which I don't understand. I tried using an explicit interface implementation but, that wound up making me remove my where constraint.
The constraints for type parameter 'TD' of method 'LiveWire.Data.Repositories.LiveWireRepositoryBase.GetData()' must match the constraints for type parameter 'TD' of interface method 'LiveWire.Data.Repositories.ILiveWireRepository.GetData()'. Consider using an explicit interface implementation instead. C:\projects\LiveWire\Solution\LiveWire.Data\Repositories\LiveWireRepositoryBase.cs 32 31 LiveWire.Data

You'll be able to make this method compile by changing the class's signature to
public sealed class MyCache<T> where T : ILiveWireModel
(or, if the class is in a different namespace, where T : LiveWire.Model.ILiveWireModel).
That said, I'm not sure that this change will solve your problem. I have only seen a few snippets of your project's code, so I may be wrong, and take the following with a grain of salt:
Is it really the best design to keep GUID-keyed and integer-keyed values in the same cache? Presumably, you're taking data from two different sources, one which uses GUID keys and one which uses integer keys. But in the future, what if you add a third source, which also uses integer keys? The keys from the two integer-key sources could clash, and your cache would always be wrong for some queries. Personally, I'd maintain a second table or function (maybe keep a table of mappings for integer-valued keys, just pass through the GUID-valued keys) somewhere that knows the mapping from objects to keys, and use that function whenever I need to check if an object is cached. All the rest of the time, then, your cache could work directly in terms of keys and values, and not have to mess with different types of keys.

The exception you get at this stage just says that the interface definition
IEnumerable<T> GetData<TD>();
hasn't got the same constraints (i.e. the where) for the type parameter TD as the implementation
public IEnumerable<T> GetData<TD>() where TD : ILiveWireModel
You need to put the same constraint in the interface.

public IEnumerable<T> GetData<T>() where T:LiveWire.Model.ILiveWireModel {
//.../
}
Specialization of generics.

You need to fix the declaration first
public IEnumerable<T> GetData<T>()
then, in order to know what you can use ON T, you have to tell it what T is allowed to be.
public IEnumerable<T> GetData<T>() where T : ILiveWireModel
Finally, you haven't told us what var data actually contains, that would be inside of the GetCachedData and the LoadData Functions, which you dont pass T into and we dont have any idea what it returns.
I would expect to see something like this though
public IEnumerable<T> GetData<T>() where T : ILiveWireModel
{
var data = GetCachedData<T>();
if (data == null)
{
data = LoadData<T>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}

Related

Using Generics to avoid casting when caching different types

I am using ASP.NET Core and Redis Cache. I am trying to store different types of different objects in the cache and I want to avoid explicit casting.
This is My wrapper For the Redis Cache
public class RedisCacheStorage : Contracts.ICacheStorage
{
private CachingFramework.Redis.Context _context = null;
public RedisCacheStorage(string configuration)
{
_context = new CachingFramework.Redis.Context(configuration, new CachingFramework.Redis.Serializers.JsonSerializer());
}
public void SetItem<T>(string key, T value)
{
_context.Cache.SetObject<T>(key, value);
}
public T GetItem<T>(string key)
{
return _context.Cache.GetObject<T>(key);
}
public T GetItem<T>(string key, Func<T> loadCacheFunc)
{
return _context.Cache.FetchObject<T>(key, loadCacheFunc);
}
Then I Inject ICacheStorage in CacheManager (which implements ICacheManager). I am trying to isolate the dependencies and keeping the CacheStorage simple, so when I need to change the cache type I just implement the ICacheStorage. In CacheManager, we are injecting all Services that get some data when special keys are passed.
CacheManager:
public class CacheManager : Contracts.ICacheManager
{
private Contracts.ICacheStorage _cacheStorage;
private SecurityCore.ServiceContracts.IParametersService _paramService;
public CacheManager(Contracts.ICacheStorage cacheStorage, SecurityCore.ServiceContracts.IParametersService paramService)
{
_cacheStorage = cacheStorage;
_paramService = paramService;
}
public Object GetItem(string key)
{
if (key == Constants.CacheKeys.SecuritySystemParams)
return _cacheStorage.GetItem<Dictionary<string, string>>(key, _paramService.GetSystemParameters);
//if (key == Constants.CacheKeys.EffectivePermissions)
// return List of Effective Permissions
return _cacheStorage.GetItem<Object>(key);
}
_cacheStorage.GetItem<Dictionary<string, string>>(key, _paramService.GetSystemParameters);
Passes a function that uses the Fetch Method of the Redis, if the cache was empty, it calls the service, then store the data in cache and return it back.
My Problem is that I need to avoid casting, because I might be returning different objects, How i can keep using Generics, So I pass the type of the object returned.
As you see below a compilation error, due to cannot convert the type object to Dictionay and this needs explicit casting to be resolved.
Is there better, elegant way to implement the Whole idea?
Read the error message.
You need to explicitly specify the type parameter.
You can make this much better with type-safe keys:
class CacheKey<T> {
public string Name { get; }
public string ToString() => Name;
public CacheKey(string name) { Name = name; }
}
public T GetItem<T>(CacheKey<T> key) { ... }
public CacheKey<Dictionary<string, string>> SecuritySystemParams { get; } = new CacheKey<Dictionary<string, string>>("SecuritySystemParams");
This will let GetItem() infer T from the key, and will prevent you from passing the wrong type.

C# Generic Interface and Factory Pattern

I am trying to create a Generic interface where the parameter type of one of the methods is defined by the generic
EDIT
I've changed the question slightly after realising I have probably confused matters by specifying a type parameter in the Factory creation method. What I have is two types of API calls that I need to make to a 3rd party API. The first retrieves a record from the API using an Id that is an int. The second also retrieves a record from the API but the Id is a string (guid). I have a class for each record type (ClientEntity and InvoiceEntity) that both implement a Generic Interface where I pass in the Id type
This is the Interface in which I declare a Method with an id Parameter
public interface IGeneric<TId>
{
void ProcessEntity(TId id);
}
I implement the interface in a couple of classes, one sets the id to be an int, the other a string.
public class ClientEntity: IGeneric<int> // Record with Id that is an int
{
public void ProcessEntity(int id)
{
Console.WriteLine(id);
// call 3rd party API with int Id
}
}
public class InvoiceEntity: IGeneric<string> // Record with Id that is a string (guid)
{
public void ProcessEntity(string id)
{
Console.WriteLine(id);
// call 3rd party API with string Id
}
}
What I would like to know is how do I use this within a factory pattern?
public static class GenericFactory
{
public static IGeneric<WhatGoesHere> CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (type == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
}
The objective is to use the factory to instantiate the correct class so that I can call the ProcessEntity method
EDIT
I don't want to have to pass in the Generic type to the factory method because the class that is created by the factory should handle that. When I create the object, I don't know what Id type is required, I want the factory to handle that
e.g.
var myGeneric = GenericFactory.CreateGeneric("Client");
myGeneric.ProcessEntity("guid")
or
var myGeneric = GenericFactory.CreateGeneric("Invoice");
myGeneric.ProcessEntity(1234)
I hope that makes sense
You should be able to do something like this:
public static class GenericFactory
{
public static IGeneric<T> CreateGeneric<T>()
{
if (typeof(T) == typeof(string))
{
return (IGeneric<T>) new GenericString();
}
if (typeof(T) == typeof(int))
{
return (IGeneric<T>) new GenericInt();
}
throw new InvalidOperationException();
}
}
You would use it like this:
var a = GenericFactory.CreateGeneric<string>();
var b = GenericFactory.CreateGeneric<int>();
Note that this uses a strongly-typed call rather than passing in the type name as a string (which may or may not be what you actually want).
If instead you want to pass a string for the type name, you will have to return an object because there is no way to return the actual type:
public static object CreateGeneric(string type)
{
switch (type)
{
case "string": return new GenericString();
case "int": return new GenericInt();
default: throw new InvalidOperationException("Invalid type specified.");
}
}
Obviously if you have an object you would normally have to cast it to the right type in order to use it (which requires that you know the actual type).
Alternatively, you could use reflection to determine what methods it contains, and call them that way. But then you'd still need to know the type in order to pass a parameter of the right type.
I think that what you are attempting to do here is not the right approach, which you will discover once you start trying to use it.
Hacky solution: Use dynamic
Nevertheless, there is one way you can get something close to what you want: Use dynamic as follows (assuming that you are using the object CreateGeneric(string type) factory method from above):
dynamic a = GenericFactory.CreateGeneric("string");
dynamic b = GenericFactory.CreateGeneric("int");
a.ProcessEntity("A string");
b.ProcessEntity(12345);
Be aware that dynamic uses reflection and code generation behind the scenes, which can make the initial calls relatively slow.
Also be aware that if you pass the wrong type to a method accessed via dynamic, you'll get a nasty runtime exception:
dynamic a = GenericFactory.CreateGeneric("string");
a.ProcessEntity(12345); // Wrong parameter type!
If you run that code, you get this kind of runtime exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'ConsoleApplication1.GenericString.ProcessEntity(string)' has some invalid arguments
at CallSite.Target(Closure , CallSite , Object , Int32 )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at ConsoleApplication1.Program.Main() in D:\Test\CS6\ConsoleApplication1\Program.cs:line 71
Usually for that Factory using some DI container (DI can be useful, for example, when GenericInt or GenericString has dependencies), but to demonstrate just Idea how you can resolve this:
void Main()
{
GenericFactory.CreateGeneric<int>();
GenericFactory.CreateGeneric<string>();
}
public static class GenericFactory
{
private static Dictionary<Type, Type> registeredTypes = new Dictionary<System.Type, System.Type>();
static GenericFactory()
{
registeredTypes.Add(typeof(int), typeof(GenericInt));
registeredTypes.Add(typeof(string), typeof(GenericString));
}
public static IGeneric<T> CreateGeneric<T>()
{
var t = typeof(T);
if (registeredTypes.ContainsKey(t) == false) throw new NotSupportedException();
var typeToCreate = registeredTypes[t];
return Activator.CreateInstance(typeToCreate, true) as IGeneric<T>;
}
}
public interface IGeneric<TId>
{
TId Id { get; set; }
void ProcessEntity(TId id);
}
public class GenericInt : IGeneric<int>
{
public int Id { get; set; }
public void ProcessEntity(int id)
{
Console.WriteLine(id);
}
}
public class GenericString : IGeneric<string>
{
public string Id { get; set; }
public void ProcessEntity(string id)
{
Console.WriteLine(id);
}
}
The answer marked correct is fine if you want to use Static class but but what if you
want to return an DI injected type instead of newing an object? I suggest the
following!
public interface IGenericFactory
{
IGeneric<T> GetGeneric<T>() where T : class;
}
public class GenericFactory: IGenericFactory
{
private readonly IGeneric<int> intGeneric;
private readonly IGeneric<string> stringGeneric;
public GenericFactory(IGeneric<int> intG, IGeneric<string> stringG)
{
intGeneric = intG;
stringG = stringG;
}
public IGeneric<T> GetGeneric<T>() where T : class
{
if (typeof(T) == typeof(IGeneric<int>))
return (IGeneric<T>)Convert.ChangeType(intGeneric, typeof(IGeneric<T>));
if (typeof(T) == typeof(IGeneric<string>))
return (IGeneric<T>)Convert.ChangeType(stringGeneric,typeof(IGeneric<T>));
else
throw new NotSupportedException();
}
}
Please note i simply injected the two expected return types for clarity in the constructor. I could have implemented the factory as a Dictionary and injected the return objects into this Dictionary. Hope it helps.
I'm thinking you don't want to have to enter the type parameter similar to the LINQ methods. However the magic behind that happens because the type parameter is used in the normal parameter definitions. For example in the ToList<string>() method you can see that TSource is used between the parenthesis.
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
That's how the compiler knows that you want a List<string> if you call ToList() instead of ToList<string>() when called from an IEnumerable<string>
However, I don't think you need a generic type parameter in your factory method at all. All you have to do is create a non-generic version of your TGeneric<TId>
public interface IGeneric { }
public interface IGeneric<TId> : IGeneric
{
void ProcessEntity(TId id);
}
And remove the <WhatGoesHere> from the CreateGeneric method:
public static IGeneric CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (recordType == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
If the function does not know the type, make it generic.
If the children are generics of different types (<int>, <string>), return object and cast inside the same factory class (Factory<T>), It is safe by typeof.
Personally, I prefer to specify the type with generics, without using an additional parameter, eg a string.
public class Program
{
public static void Main(string[] args)
{
List<Number> something = new();
Do(something);
}
public static void Do<T>(List<T> list)
{
list.Add(Factory<T>.Create());
}
}
public abstract class Factory<T>
{
private static Object ConcreteF()
{
if (typeof(T) == typeof(Number))
return new ChildGenericNumber();
throw new Exception("");
}
public static T Create()
{
return (Factory<T>)ConcreteF()).Build();
}
protected abstract T Build();
}

Trying to Utilise a generic <T> collection

I am using C# and I thought I finally had the chance to understand a Generic type. I have several strongly typed objects that need the same static method. Rather than create one static method for each type I thought I could make it generic. Something I have never done and really wanted too.
Here is where I invoke it.
bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
Here is my static method which resides in a static class called Utilities.
public static bool GetDuplicates<T>(List<T> pBookings)
{
foreach (var item in pBookings)
{
var myVal = item.bookingId
}
return true;
}
So I want to get at the values within var item inside the foreach loop so I can do comparisons. It's definately passed pBookings because I can hover and they have a .Count() with a collection of my strongly typed object. I am missing something here, possibly a casting process. I was wondering if anyone could advise me where I am coming up short.
var myVal = item.bookingId - I cannot get the bookingID from item because I am lacking in some basic understanding here. bookingId doesn't exist, I just get access to extension methods such as .toString and .equals
ANSWER OF SORTS What I did based on all of your really helpful assistance. I utilised Anderson Pimentel. I'm probably still off the mark but wanted to garner anyones thoughts here.
So basically I have several booking models, all need checking for duplicates. I really wanted to understand Generics in this way. So what I did is. Created a base class.
public class BookingBaseModel
{
public int BookingID { get; set; }
public DateTime BookingStartDateTime { get; set; }
public DateTime BookingEndDateTime { get; set; }
}
Then had my booking classes all inherit whats common to all. Like this...
public class RoomBookingModel : BookingBaseModel
{
public string RoomName{ get; set; }
}
public class vehicleBookingModel : BookingBaseModel
{
public string vehicleName{ get; set; }
}
Then in my utilities static helper I did this..
public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
{
foreach (var item in items)
{
int myId = item.ID;
DateTime startDateTime = item.BookingStartDateTime;
DateTime endDateTime = item.BookingEndDateTime;
//Do you logic here
}
}
Then finally did something like this in corresponding controller action.
RoomController...
Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
VehicleController....
Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);
Is this basically how we go about using generics in this way?
The compiler has no hint of what type is T. If you have a base class (or an Interface) which has the bookingId attribute, like BaseModel, you can constrain the generic type like the following:
public class BaseModel
{
public int Id { get; set; }
}
public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{
foreach (var item in items)
{
var myId = item.Id;
//Do you logic here
}
return true;
}
Once you're inside your GetDuplicates method, you have lost all knowledge of the RoomBookingModel type. That's the point of generic methods - they should be able to act on whatever type has been passed in to them, e.g. the logic within them should be generic across any type.
So your foreach loop is fine - you know you've been given a list of something, and you know lists can be iterated. But inside that foreach, item is just a T. You don't know what actual type it is because any type could have been passed in. So it doesn't make sense to access a specific property or method off of item - for example, what if I called GetDuplicates passing in a List<int>? It wouldn't have a bookingId property.
As written by others, you don't know anything of T. A classical solution, used by LINQ (see for example GroupBy) is to have your method receive a delegate that does the key-extraction, like:
public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector)
{
foreach (var item in pBookings)
{
TKey key = selector(item);
}
return true;
}
You then use it like:
GetDuplicates(pBookings, p => p.bookingId);
If you like to use a generic method, you have to provide also a generic method, which is able to generate a key out of the specified type T. Luckily we have LINQ which already provides the needed parts to build your generic method:
internal class Extensions
{
public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return source.GroupBy(keySelector)
.Where(group => group.Skip(1).Any())
.SelectMany(group => group);
}
public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return GetDuplicates(source, keySelector).Any();
}
}
By having this (and type inference) you can use these methods e.g. by calling:
var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
if(hasDuplicates)
{
Console.WriteLine("Duplicates found:");
foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
{
Console.WriteLine(duplicate);
}
}
I wonder if generics is really the tool for the job here. Your needs would be better served if each of your strongly typed objects shared a common interface.
"I have several strongly typed objects that need the same static method."
In this situation, all of the classes must share a common feature, such as, for instance, a property BookingId.
So, you'd need to formalize this by extracting this common interface:
public interface IBooking
{
int BookingId{ get; }
}
Make sure that every one of your strongly typed items implements the interface:
public class RoomBooking : IBooking
{
//etc...
}
And now make your static method accept IBooking instances:
public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
{
//does pBookings contain items with duplicate BookingId values?
return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
}
An easy read that isn't obfuscated by the unnecessary use of generics.
Since there are no constraints or hints about what T is, the compiler does not have enough information. Consider
bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
Clearly an int does not have a bookingId member.
Every possible specific type for T would have to have a common base class or interface that has a bookingId, and even then you would have to add a generic constraint to your method signature to access that.
Perhaps you are looking for something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Duplicates
{
public static class EnumerableExtensions
{
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
{
var hashSet = new HashSet<I>(comparer);
foreach (var item in enumerable)
{
var identity = identityGetter(item);
if (hashSet.Contains(identity)) return true;
hashSet.Add(identity);
}
return false;
}
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
{
return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
}
}
public class Booking
{
public int BookingId { get; set; }
public string BookingName { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var bookings = new List<Booking>()
{
new Booking { BookingId = 1, BookingName = "Booking 1" },
new Booking { BookingId = 1, BookingName = "Booking 1" }
};
Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
var customers = new List<Customer>()
{
new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
};
Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
}
}
}

Derived interface from generic method

I'm trying to do this:
public interface IVirtualInterface{ }
public interface IFabricationInfo : IVirtualInterface
{
int Type { get; set; }
int Requirement { get; set; }
}
public interface ICoatingInfo : IVirtualInterface
{
int Type { get; set; }
int Requirement { get; set; }
}
public class FabInfo : IFabricationInfo
{
public int Requirement
{
get { return 1; }
set { }
}
public int Type
{
get {return 1;}
set{}
}
}
public class CoatInfo : ICoatingInfo
{
public int Type
{
get { return 1; }
set { }
}
public int Requirement
{
get { return 1; }
set { }
}
}
public class BusinessObj
{
public T VirtualInterface<T>() where T : IVirtualInterface
{
Type targetInterface = typeof(T);
if (targetInterface.IsAssignableFrom(typeof(IFabricationInfo)))
{
var oFI = new FabInfo();
return (T)oFI;
}
if (targetInterface.IsAssignableFrom(typeof(ICoatingInfo)))
{
var oCI = new CoatInfo();
return (T)oCI;
}
return default(T);
}
}
But getting a compiler error: Canot convert type 'GenericIntf.FabInfo' to T
How do I fix this?
thanks
Sunit
Assuming all IVirtualInterface implementations will have a default constructor (as in your example), you can do this instead:
public T VirtualInterface<T>() where T : IVirtualInterface, new()
{
return new T();
}
Simples!
EDIT:
Exactly what you're trying to achieve is difficult to determine from the code you've posted. Why isn't VirtualInterface static (implies all business objects inherit this method which seems odd)? If you need o be able to parameterised constructors for your IVirtualInterface implementations, where would those parameter values come from (you're not passing any into the VirtualInterface method)?
If you just want to avoid cluttering up intellisense (a poor reason for trying something like this IMHO) but also want to maintain support for parameteried constructors, then how about this:
public T VirtualInterface<T>(Func<T> constructor) where T : IVirtualInterface
{
return constructor();
}
With usage:
IFabricationInfo fabInfo =
new BusinessObj().VirtualInterface<IFabricationInfo>(() => new FabInfo());
Overall though, and without enough information to make a solid judgement, I'd have to say that this smells.
The fact that T and FabInfo both implement IVirtualInterface does not mean you can perform a cast between the two types. For example if T is CoatInfo, then it is not compatible type with FabInfo.
Interfaces allow you to treat different objects as similar types based on the methods they provide. However, this does not mean that you can perform casts between these two types as their actual implementation can vary greatly.
Edit: After re-reading your method again, I see that you are checking the type first. The problem is that the compiler doesn't know you are performing that logic before you try to make that cast. If you are writing a generic method and are checking the type of T, you are likely misusing the concept of generics. See the other answers for the way you should be creating new instances of T.
You can get around this error by first casting to object before casting to T e.g.
return (T)(object)oFI;
and similarly for CoatInfo
However I think switching on a generic type is an abuse, since if you want a limited number of possible return values, you could make the options explicit e.g.
public IFabricationInfo GetFabricationInfo()
{
return new FabInfo();
}

C# How to make public getters and setters and private methods for a collection?

I'd like to have a class "A" with a (for example) SortedList collection "SrtdLst" property, and inside this class "A" allow the addition or subtraction of "SrtdLst" items. But in a instance of the class "A", only allow to get or set the content of the items, not to add new items or subtract the existing ones. In code:
class A
{
public SortedList<string, string> SrtdLst = new SortedList<string, string>();
public A()
{
// This must work:
SrtdLst.Add("KeyA", "ValueA");
// This too:
SrtdLst["KeyA"] = "ValueAAA";
}
}
class B
{
public A a = new A();
public B()
{
// I want the following code to fail:
a.SrtdLst.Add("KeyB", "ValueB");
// But this must work:
a.SrtdLst["KeyA"] = "ValueBBB";
}
}
UPDATE: I want to create a class like System.Data.SqlClient.SqlCommand. For the Stored Procedures you can use the member "DeriveParameters" that fills a collection of "Parameters", so only the value of each item can be modified.
How can this be done?
If you want to ban the modifying operations at compile time, you need a type-safe solution.
Declare an interface for the publicly allowed operations. Use that interface as the property type.
public interface IReadOnlyList<T>
{
T this[int index] { get; }
int Count { get; }
}
Then declare a class that implements that interface and inherits from the standard collection class.
public class SafeList<T> : List<T>, IReadOnlyList<T> { }
Assuming you get the interface definition right, you won't need to implement anything by hand, as the base class already provides the implementations.
Use that derived class as the type of the field that stores the property value.
public class A
{
private SafeList<string> _list = new SafeList<string>();
public IReadOnlyList<string>
{
get { return _list; }
}
}
Within class A, you can use _list directly, and so modify the contents. Clients of class A will only be able to use the subset of operations available via IReadOnlyList<T>.
For your example, you're using SortedList instead of List, so the interface probably needs to be
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
I've made it inherit IEnumerable as well, which is readonly anyway, so is perfectly safe. The safe class would then be:
public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }
But otherwise it's the same idea.
Update: just noticed that (for some reason I can't fathom) you don't want to ban modifying operations - you just want to ban SOME modifying operations. Very strange, but it's still the same solution. Whatever operations you want to allow, "open them up" in the interface:
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; set; }
}
Of course, that's the wrong name for the interface now... why on earth would you want to ban adding via Add but not ban it via the indexer? (The indexer can be used to add items, just as the Add method can.)
Update
From your comment I think you mean that you want to allow assignment to the value of an existing key/value pair, but disallow assignment to a previously unknown key. Obviously as keys are specified at runtime by strings, there's no way to catch that at compile time. So you may as well go for runtime checking:
public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
IDictionary<TKey, TValue> _realDictionary;
public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
{
_realDictionary = realDictionary;
}
public TValue this[TKey key]
{
get { return _realDictionary[key]; }
set
{
if (!_realDictionary.Contains(key))
throw new InvalidOperationException();
_realDictionary[key] = value;
}
}
// Implement Add so it always throws InvalidOperationException
// implement all other dictionary methods to forward onto _realDictionary
}
Any time you have an ordinary dictionary and you want to hand it to some method that you don't trust to update the existing values, wrap it in one of these.
EDIT: Original answer is below. As earwicker points out, I hadn't noticed that you aren't asking for it to be readonly - just to prevent the Add operation. That doesn't sound like a good idea to me, as the only difference between Add and the indexer-setter is that Add throws an exception if the element is already present. That could easily be faked up by the caller anyway.
Why do you want to restrict just that one operation?
Original answer
For one thing, don't use public fields. That's a surefire way to run into problems.
It looks like you want a read-only wrapper class round an arbitrary IDictionary. You can then have a public property which returns the wrapper, while you access the private variable from within your class. For example:
class A
{
private SortedList<string, string> sortedList = new SortedList<string, string>();
public IDictionary<string, string> SortedList
{
get { return new ReadOnlyDictionaryWrapper(sortedList);
}
public A()
{
sortedList.Add("KeyA", "ValueA");
sortedList["KeyA"] = "ValueAAA";
}
}
Now you've just got to find a ReadOnlyDictionary implementation... I can't implement it right now, but I'll be back later if necessary...
Just make the list private, and expose it as an indexer:
class A {
private SortedList<string, string> _list;
public A() {
_list = new SortedList<string, string>()
}
public string this[string key] {
get {
return _list[key];
}
set {
_list[key] = value;
}
}
}
Now you can only access the items using the index:
a["KeyA"] = "ValueBBB";
However, as the indexer of the list allows creation of new items, you would have to add code in the indexer to prevent that if you don't want that do be possible.
If the keys are known outside of the class then you can add a ChangeItem(key, newValue) and ReadItem(key) to your wrapper class. Then keep the SortedList private to the class.

Categories

Resources